1 /******************************************************************************
2 * *
3 * easycap_ioctl.c *
4 * *
5 ******************************************************************************/
6 /*
7 *
8 * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
9 *
10 *
11 * This is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this software; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26 /*****************************************************************************/
27
28 #include "easycap.h"
29
30 /*--------------------------------------------------------------------------*/
31 /*
32 * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
33 * FOLLOWING:
34 * peasycap->standard_offset
35 * peasycap->inputset[peasycap->input].standard_offset
36 * peasycap->fps
37 * peasycap->usec
38 * peasycap->tolerate
39 * peasycap->skip
40 */
41 /*---------------------------------------------------------------------------*/
adjust_standard(struct easycap * peasycap,v4l2_std_id std_id)42 int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
43 {
44 struct easycap_standard const *peasycap_standard;
45 u16 reg, set;
46 int ir, rc, need, k;
47 unsigned int itwas, isnow;
48 bool resubmit;
49
50 if (!peasycap) {
51 SAY("ERROR: peasycap is NULL\n");
52 return -EFAULT;
53 }
54 if (!peasycap->pusb_device) {
55 SAM("ERROR: peasycap->pusb_device is NULL\n");
56 return -EFAULT;
57 }
58 peasycap_standard = &easycap_standard[0];
59 while (0xFFFF != peasycap_standard->mask) {
60 if (std_id == peasycap_standard->v4l2_standard.id)
61 break;
62 peasycap_standard++;
63 }
64 if (0xFFFF == peasycap_standard->mask) {
65 peasycap_standard = &easycap_standard[0];
66 while (0xFFFF != peasycap_standard->mask) {
67 if (std_id & peasycap_standard->v4l2_standard.id)
68 break;
69 peasycap_standard++;
70 }
71 }
72 if (0xFFFF == peasycap_standard->mask) {
73 SAM("ERROR: 0x%08X=std_id: standard not found\n",
74 (unsigned int)std_id);
75 return -EINVAL;
76 }
77 SAM("selected standard: %s\n",
78 &(peasycap_standard->v4l2_standard.name[0]));
79 if (peasycap->standard_offset == peasycap_standard - easycap_standard) {
80 SAM("requested standard already in effect\n");
81 return 0;
82 }
83 peasycap->standard_offset = peasycap_standard - easycap_standard;
84 for (k = 0; k < INPUT_MANY; k++) {
85 if (!peasycap->inputset[k].standard_offset_ok) {
86 peasycap->inputset[k].standard_offset =
87 peasycap->standard_offset;
88 }
89 }
90 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
91 peasycap->inputset[peasycap->input].standard_offset =
92 peasycap->standard_offset;
93 peasycap->inputset[peasycap->input].standard_offset_ok = 1;
94 } else
95 JOM(8, "%i=peasycap->input\n", peasycap->input);
96
97 peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator /
98 peasycap_standard->v4l2_standard.frameperiod.numerator;
99 switch (peasycap->fps) {
100 case 6:
101 case 30: {
102 peasycap->ntsc = true;
103 break;
104 }
105 case 5:
106 case 25: {
107 peasycap->ntsc = false;
108 break;
109 }
110 default: {
111 SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
112 return -ENOENT;
113 }
114 }
115 JOM(8, "%i frames-per-second\n", peasycap->fps);
116 if (0x8000 & peasycap_standard->mask) {
117 peasycap->skip = 5;
118 peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
119 peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
120 } else {
121 peasycap->skip = 0;
122 peasycap->usec = 1000000 / (2 * peasycap->fps);
123 peasycap->tolerate = 1000 * (25 / peasycap->fps);
124 }
125 if (peasycap->video_isoc_streaming) {
126 resubmit = true;
127 easycap_video_kill_urbs(peasycap);
128 } else
129 resubmit = false;
130 /*--------------------------------------------------------------------------*/
131 /*
132 * SAA7113H DATASHEET PAGE 44, TABLE 42
133 */
134 /*--------------------------------------------------------------------------*/
135 need = 0;
136 itwas = 0;
137 reg = 0x00;
138 set = 0x00;
139 switch (peasycap_standard->mask & 0x000F) {
140 case NTSC_M_JP: {
141 reg = 0x0A;
142 set = 0x95;
143 ir = read_saa(peasycap->pusb_device, reg);
144 if (0 > ir)
145 SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
146 else
147 itwas = (unsigned int)ir;
148 rc = write_saa(peasycap->pusb_device, reg, set);
149 if (rc)
150 SAM("ERROR: failed to set SAA register "
151 "0x%02X to 0x%02X for JP standard\n", reg, set);
152 else {
153 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
154 if (0 > ir)
155 JOM(8, "SAA register 0x%02X changed "
156 "to 0x%02X\n", reg, isnow);
157 else
158 JOM(8, "SAA register 0x%02X changed "
159 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
160 }
161
162 reg = 0x0B;
163 set = 0x48;
164 ir = read_saa(peasycap->pusb_device, reg);
165 if (0 > ir)
166 SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
167 else
168 itwas = (unsigned int)ir;
169 rc = write_saa(peasycap->pusb_device, reg, set);
170 if (rc)
171 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X "
172 "for JP standard\n", reg, set);
173 else {
174 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
175 if (0 > ir)
176 JOM(8, "SAA register 0x%02X changed "
177 "to 0x%02X\n", reg, isnow);
178 else
179 JOM(8, "SAA register 0x%02X changed "
180 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
181 }
182 /*--------------------------------------------------------------------------*/
183 /*
184 * NOTE: NO break HERE: RUN ON TO NEXT CASE
185 */
186 /*--------------------------------------------------------------------------*/
187 }
188 case NTSC_M:
189 case PAL_BGHIN: {
190 reg = 0x0E;
191 set = 0x01;
192 need = 1;
193 break;
194 }
195 case NTSC_N_443:
196 case PAL_60: {
197 reg = 0x0E;
198 set = 0x11;
199 need = 1;
200 break;
201 }
202 case NTSC_443:
203 case PAL_Nc: {
204 reg = 0x0E;
205 set = 0x21;
206 need = 1;
207 break;
208 }
209 case NTSC_N:
210 case PAL_M: {
211 reg = 0x0E;
212 set = 0x31;
213 need = 1;
214 break;
215 }
216 case SECAM: {
217 reg = 0x0E;
218 set = 0x51;
219 need = 1;
220 break;
221 }
222 default:
223 break;
224 }
225 /*--------------------------------------------------------------------------*/
226 if (need) {
227 ir = read_saa(peasycap->pusb_device, reg);
228 if (0 > ir)
229 SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
230 else
231 itwas = (unsigned int)ir;
232 rc = write_saa(peasycap->pusb_device, reg, set);
233 if (0 != write_saa(peasycap->pusb_device, reg, set)) {
234 SAM("ERROR: failed to set SAA register "
235 "0x%02X to 0x%02X for table 42\n", reg, set);
236 } else {
237 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
238 if (0 > ir)
239 JOM(8, "SAA register 0x%02X changed "
240 "to 0x%02X\n", reg, isnow);
241 else
242 JOM(8, "SAA register 0x%02X changed "
243 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
244 }
245 }
246 /*--------------------------------------------------------------------------*/
247 /*
248 * SAA7113H DATASHEET PAGE 41
249 */
250 /*--------------------------------------------------------------------------*/
251 reg = 0x08;
252 ir = read_saa(peasycap->pusb_device, reg);
253 if (0 > ir)
254 SAM("ERROR: failed to read SAA register 0x%02X "
255 "so cannot reset\n", reg);
256 else {
257 itwas = (unsigned int)ir;
258 if (peasycap_standard->mask & 0x0001)
259 set = itwas | 0x40 ;
260 else
261 set = itwas & ~0x40 ;
262 rc = write_saa(peasycap->pusb_device, reg, set);
263 if (rc)
264 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
265 reg, set);
266 else {
267 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
268 if (0 > ir)
269 JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
270 reg, isnow);
271 else
272 JOM(8, "SAA register 0x%02X changed "
273 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
274 }
275 }
276 /*--------------------------------------------------------------------------*/
277 /*
278 * SAA7113H DATASHEET PAGE 51, TABLE 57
279 */
280 /*---------------------------------------------------------------------------*/
281 reg = 0x40;
282 ir = read_saa(peasycap->pusb_device, reg);
283 if (0 > ir)
284 SAM("ERROR: failed to read SAA register 0x%02X "
285 "so cannot reset\n", reg);
286 else {
287 itwas = (unsigned int)ir;
288 if (peasycap_standard->mask & 0x0001)
289 set = itwas | 0x80 ;
290 else
291 set = itwas & ~0x80 ;
292 rc = write_saa(peasycap->pusb_device, reg, set);
293 if (rc)
294 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
295 reg, set);
296 else {
297 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
298 if (0 > ir)
299 JOM(8, "SAA register 0x%02X changed to 0x%02X\n",
300 reg, isnow);
301 else
302 JOM(8, "SAA register 0x%02X changed "
303 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
304 }
305 }
306 /*--------------------------------------------------------------------------*/
307 /*
308 * SAA7113H DATASHEET PAGE 53, TABLE 66
309 */
310 /*--------------------------------------------------------------------------*/
311 reg = 0x5A;
312 ir = read_saa(peasycap->pusb_device, reg);
313 if (0 > ir)
314 SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
315 itwas = (unsigned int)ir;
316 if (peasycap_standard->mask & 0x0001)
317 set = 0x0A ;
318 else
319 set = 0x07 ;
320 if (0 != write_saa(peasycap->pusb_device, reg, set))
321 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n",
322 reg, set);
323 else {
324 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
325 if (0 > ir)
326 JOM(8, "SAA register 0x%02X changed "
327 "to 0x%02X\n", reg, isnow);
328 else
329 JOM(8, "SAA register 0x%02X changed "
330 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
331 }
332 if (resubmit)
333 easycap_video_submit_urbs(peasycap);
334 return 0;
335 }
336 /*****************************************************************************/
337 /*--------------------------------------------------------------------------*/
338 /*
339 * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
340 * A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
341 *
342 * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
343 * THIS ROUTINE UPDATES THE FOLLOWING:
344 * peasycap->format_offset
345 * peasycap->inputset[peasycap->input].format_offset
346 * peasycap->pixelformat
347 * peasycap->height
348 * peasycap->width
349 * peasycap->bytesperpixel
350 * peasycap->byteswaporder
351 * peasycap->decimatepixel
352 * peasycap->frame_buffer_used
353 * peasycap->videofieldamount
354 * peasycap->offerfields
355 *
356 * IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
357 * IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
358 * ERRORS RETURN A NEGATIVE NUMBER.
359 */
360 /*--------------------------------------------------------------------------*/
adjust_format(struct easycap * peasycap,u32 width,u32 height,u32 pixelformat,int field,bool try)361 int adjust_format(struct easycap *peasycap,
362 u32 width, u32 height, u32 pixelformat, int field, bool try)
363 {
364 struct easycap_format *peasycap_format, *peasycap_best_format;
365 u16 mask;
366 struct usb_device *p;
367 int miss, multiplier, best, k;
368 char bf[5], fo[32], *pc;
369 u32 uc;
370 bool resubmit;
371
372 if (!peasycap) {
373 SAY("ERROR: peasycap is NULL\n");
374 return -EFAULT;
375 }
376 if (0 > peasycap->standard_offset) {
377 JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
378 return -EBUSY;
379 }
380 p = peasycap->pusb_device;
381 if (!p) {
382 SAM("ERROR: peaycap->pusb_device is NULL\n");
383 return -EFAULT;
384 }
385 pc = &bf[0];
386 uc = pixelformat;
387 memcpy((void *)pc, (void *)(&uc), 4);
388 bf[4] = 0;
389 mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
390 SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n",
391 width, height, pc, pixelformat, field, mask);
392 switch (field) {
393 case V4L2_FIELD_ANY: {
394 strcpy(&fo[0], "V4L2_FIELD_ANY ");
395 break;
396 }
397 case V4L2_FIELD_NONE: {
398 strcpy(&fo[0], "V4L2_FIELD_NONE");
399 break;
400 }
401 case V4L2_FIELD_TOP: {
402 strcpy(&fo[0], "V4L2_FIELD_TOP");
403 break;
404 }
405 case V4L2_FIELD_BOTTOM: {
406 strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
407 break;
408 }
409 case V4L2_FIELD_INTERLACED: {
410 strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
411 break;
412 }
413 case V4L2_FIELD_SEQ_TB: {
414 strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
415 break;
416 }
417 case V4L2_FIELD_SEQ_BT: {
418 strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
419 break;
420 }
421 case V4L2_FIELD_ALTERNATE: {
422 strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
423 break;
424 }
425 case V4L2_FIELD_INTERLACED_TB: {
426 strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
427 break;
428 }
429 case V4L2_FIELD_INTERLACED_BT: {
430 strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
431 break;
432 }
433 default: {
434 strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN ");
435 break;
436 }
437 }
438 SAM("sought: %s\n", &fo[0]);
439 if (V4L2_FIELD_ANY == field) {
440 field = V4L2_FIELD_NONE;
441 SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
442 }
443 peasycap_best_format = NULL;
444 peasycap_format = &easycap_format[0];
445 while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
446 JOM(16, ".> %i %i 0x%08X %ix%i\n",
447 peasycap_format->mask & 0x01,
448 peasycap_format->v4l2_format.fmt.pix.field,
449 peasycap_format->v4l2_format.fmt.pix.pixelformat,
450 peasycap_format->v4l2_format.fmt.pix.width,
451 peasycap_format->v4l2_format.fmt.pix.height);
452
453 if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
454 (peasycap_format->v4l2_format.fmt.pix.field == field) &&
455 (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat) &&
456 (peasycap_format->v4l2_format.fmt.pix.width == width) &&
457 (peasycap_format->v4l2_format.fmt.pix.height == height)) {
458
459 peasycap_best_format = peasycap_format;
460 break;
461 }
462 peasycap_format++;
463 }
464 if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
465 SAM("cannot do: %ix%i with standard mask 0x%02X\n",
466 width, height, mask);
467 peasycap_format = &easycap_format[0];
468 best = -1;
469 while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
470 if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) &&
471 (peasycap_format->v4l2_format.fmt.pix.field == field) &&
472 (peasycap_format->v4l2_format.fmt.pix.pixelformat == pixelformat)) {
473
474 miss = abs(peasycap_format->v4l2_format.fmt.pix.width - width);
475 if ((best > miss) || (best < 0)) {
476 best = miss;
477 peasycap_best_format = peasycap_format;
478 if (!miss)
479 break;
480 }
481 }
482 peasycap_format++;
483 }
484 if (-1 == best) {
485 SAM("cannot do %ix... with standard mask 0x%02X\n",
486 width, mask);
487 SAM("cannot do ...x%i with standard mask 0x%02X\n",
488 height, mask);
489 SAM(" %ix%i unmatched\n", width, height);
490 return peasycap->format_offset;
491 }
492 }
493 if (!peasycap_best_format) {
494 SAM("MISTAKE: peasycap_best_format is NULL");
495 return -EINVAL;
496 }
497 peasycap_format = peasycap_best_format;
498
499 /*...........................................................................*/
500 if (try)
501 return peasycap_best_format - easycap_format;
502 /*...........................................................................*/
503
504 if (false != try) {
505 SAM("MISTAKE: true==try where is should be false\n");
506 return -EINVAL;
507 }
508 SAM("actioning: %ix%i %s\n",
509 peasycap_format->v4l2_format.fmt.pix.width,
510 peasycap_format->v4l2_format.fmt.pix.height,
511 &peasycap_format->name[0]);
512 peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
513 peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
514 peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
515 peasycap->format_offset = peasycap_format - easycap_format;
516
517
518 for (k = 0; k < INPUT_MANY; k++) {
519 if (!peasycap->inputset[k].format_offset_ok) {
520 peasycap->inputset[k].format_offset =
521 peasycap->format_offset;
522 }
523 }
524 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
525 peasycap->inputset[peasycap->input].format_offset =
526 peasycap->format_offset;
527 peasycap->inputset[peasycap->input].format_offset_ok = 1;
528 } else
529 JOM(8, "%i=peasycap->input\n", peasycap->input);
530
531
532
533 peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
534 if (0x0100 & peasycap_format->mask)
535 peasycap->byteswaporder = true;
536 else
537 peasycap->byteswaporder = false;
538 if (0x0200 & peasycap_format->mask)
539 peasycap->skip = 5;
540 else
541 peasycap->skip = 0;
542 if (0x0800 & peasycap_format->mask)
543 peasycap->decimatepixel = true;
544 else
545 peasycap->decimatepixel = false;
546 if (0x1000 & peasycap_format->mask)
547 peasycap->offerfields = true;
548 else
549 peasycap->offerfields = false;
550 if (peasycap->decimatepixel)
551 multiplier = 2;
552 else
553 multiplier = 1;
554 peasycap->videofieldamount =
555 multiplier * peasycap->width * multiplier * peasycap->height;
556 peasycap->frame_buffer_used =
557 peasycap->bytesperpixel * peasycap->width * peasycap->height;
558 if (peasycap->video_isoc_streaming) {
559 resubmit = true;
560 easycap_video_kill_urbs(peasycap);
561 } else
562 resubmit = false;
563 /*---------------------------------------------------------------------------*/
564 /*
565 * PAL
566 */
567 /*---------------------------------------------------------------------------*/
568 if (0 == (0x01 & peasycap_format->mask)) {
569 if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
570 (576 == peasycap_format->v4l2_format.fmt.pix.height)) ||
571 ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
572 (288 == peasycap_format->v4l2_format.fmt.pix.height))) {
573 if (set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
574 SAM("ERROR: set_resolution() failed\n");
575 return -EINVAL;
576 }
577 } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) &&
578 (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
579 if (set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
580 SAM("ERROR: set_resolution() failed\n");
581 return -EINVAL;
582 }
583 } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
584 (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
585 ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
586 (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
587 if (set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
588 SAM("ERROR: set_resolution() failed\n");
589 return -EINVAL;
590 }
591 } else {
592 SAM("MISTAKE: bad format, cannot set resolution\n");
593 return -EINVAL;
594 }
595 /*---------------------------------------------------------------------------*/
596 /*
597 * NTSC
598 */
599 /*---------------------------------------------------------------------------*/
600 } else {
601 if (((720 == peasycap_format->v4l2_format.fmt.pix.width) &&
602 (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
603 ((360 == peasycap_format->v4l2_format.fmt.pix.width) &&
604 (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
605 if (set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
606 SAM("ERROR: set_resolution() failed\n");
607 return -EINVAL;
608 }
609 } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) &&
610 (480 == peasycap_format->v4l2_format.fmt.pix.height)) ||
611 ((320 == peasycap_format->v4l2_format.fmt.pix.width) &&
612 (240 == peasycap_format->v4l2_format.fmt.pix.height))) {
613 if (set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
614 SAM("ERROR: set_resolution() failed\n");
615 return -EINVAL;
616 }
617 } else {
618 SAM("MISTAKE: bad format, cannot set resolution\n");
619 return -EINVAL;
620 }
621 }
622 /*---------------------------------------------------------------------------*/
623 if (resubmit)
624 easycap_video_submit_urbs(peasycap);
625
626 return peasycap_best_format - easycap_format;
627 }
628 /*****************************************************************************/
adjust_brightness(struct easycap * peasycap,int value)629 int adjust_brightness(struct easycap *peasycap, int value)
630 {
631 unsigned int mood;
632 int i1, k;
633
634 if (!peasycap) {
635 SAY("ERROR: peasycap is NULL\n");
636 return -EFAULT;
637 }
638 if (!peasycap->pusb_device) {
639 SAM("ERROR: peasycap->pusb_device is NULL\n");
640 return -EFAULT;
641 }
642 i1 = 0;
643 while (0xFFFFFFFF != easycap_control[i1].id) {
644 if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
645 if ((easycap_control[i1].minimum > value) ||
646 (easycap_control[i1].maximum < value))
647 value = easycap_control[i1].default_value;
648
649 if ((easycap_control[i1].minimum <= peasycap->brightness) &&
650 (easycap_control[i1].maximum >= peasycap->brightness)) {
651 if (peasycap->brightness == value) {
652 SAM("unchanged brightness at 0x%02X\n",
653 value);
654 return 0;
655 }
656 }
657 peasycap->brightness = value;
658 for (k = 0; k < INPUT_MANY; k++) {
659 if (!peasycap->inputset[k].brightness_ok)
660 peasycap->inputset[k].brightness =
661 peasycap->brightness;
662 }
663 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
664 peasycap->inputset[peasycap->input].brightness =
665 peasycap->brightness;
666 peasycap->inputset[peasycap->input].brightness_ok = 1;
667 } else
668 JOM(8, "%i=peasycap->input\n", peasycap->input);
669
670 mood = 0x00FF & (unsigned int)peasycap->brightness;
671 if (write_saa(peasycap->pusb_device, 0x0A, mood)) {
672 SAM("WARNING: failed to adjust brightness "
673 "to 0x%02X\n", mood);
674 return -ENOENT;
675 }
676 SAM("adjusting brightness to 0x%02X\n", mood);
677 return 0;
678 }
679 i1++;
680 }
681 SAM("WARNING: failed to adjust brightness: control not found\n");
682 return -ENOENT;
683 }
684 /*****************************************************************************/
adjust_contrast(struct easycap * peasycap,int value)685 int adjust_contrast(struct easycap *peasycap, int value)
686 {
687 unsigned int mood;
688 int i1, k;
689
690 if (!peasycap) {
691 SAY("ERROR: peasycap is NULL\n");
692 return -EFAULT;
693 }
694 if (!peasycap->pusb_device) {
695 SAM("ERROR: peasycap->pusb_device is NULL\n");
696 return -EFAULT;
697 }
698 i1 = 0;
699 while (0xFFFFFFFF != easycap_control[i1].id) {
700 if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
701 if ((easycap_control[i1].minimum > value) ||
702 (easycap_control[i1].maximum < value))
703 value = easycap_control[i1].default_value;
704
705
706 if ((easycap_control[i1].minimum <= peasycap->contrast) &&
707 (easycap_control[i1].maximum >= peasycap->contrast)) {
708 if (peasycap->contrast == value) {
709 SAM("unchanged contrast at 0x%02X\n", value);
710 return 0;
711 }
712 }
713 peasycap->contrast = value;
714 for (k = 0; k < INPUT_MANY; k++) {
715 if (!peasycap->inputset[k].contrast_ok)
716 peasycap->inputset[k].contrast = peasycap->contrast;
717 }
718
719 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
720 peasycap->inputset[peasycap->input].contrast =
721 peasycap->contrast;
722 peasycap->inputset[peasycap->input].contrast_ok = 1;
723 } else
724 JOM(8, "%i=peasycap->input\n", peasycap->input);
725
726 mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
727 if (write_saa(peasycap->pusb_device, 0x0B, mood)) {
728 SAM("WARNING: failed to adjust contrast to "
729 "0x%02X\n", mood);
730 return -ENOENT;
731 }
732 SAM("adjusting contrast to 0x%02X\n", mood);
733 return 0;
734 }
735 i1++;
736 }
737 SAM("WARNING: failed to adjust contrast: control not found\n");
738 return -ENOENT;
739 }
740 /*****************************************************************************/
adjust_saturation(struct easycap * peasycap,int value)741 int adjust_saturation(struct easycap *peasycap, int value)
742 {
743 unsigned int mood;
744 int i1, k;
745
746 if (!peasycap) {
747 SAY("ERROR: peasycap is NULL\n");
748 return -EFAULT;
749 }
750 if (!peasycap->pusb_device) {
751 SAM("ERROR: peasycap->pusb_device is NULL\n");
752 return -EFAULT;
753 }
754 i1 = 0;
755 while (0xFFFFFFFF != easycap_control[i1].id) {
756 if (V4L2_CID_SATURATION == easycap_control[i1].id) {
757 if ((easycap_control[i1].minimum > value) ||
758 (easycap_control[i1].maximum < value))
759 value = easycap_control[i1].default_value;
760
761
762 if ((easycap_control[i1].minimum <= peasycap->saturation) &&
763 (easycap_control[i1].maximum >= peasycap->saturation)) {
764 if (peasycap->saturation == value) {
765 SAM("unchanged saturation at 0x%02X\n",
766 value);
767 return 0;
768 }
769 }
770 peasycap->saturation = value;
771 for (k = 0; k < INPUT_MANY; k++) {
772 if (!peasycap->inputset[k].saturation_ok)
773 peasycap->inputset[k].saturation =
774 peasycap->saturation;
775 }
776 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
777 peasycap->inputset[peasycap->input].saturation =
778 peasycap->saturation;
779 peasycap->inputset[peasycap->input].saturation_ok = 1;
780 } else
781 JOM(8, "%i=peasycap->input\n", peasycap->input);
782 mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
783 if (write_saa(peasycap->pusb_device, 0x0C, mood)) {
784 SAM("WARNING: failed to adjust saturation to "
785 "0x%02X\n", mood);
786 return -ENOENT;
787 }
788 SAM("adjusting saturation to 0x%02X\n", mood);
789 return 0;
790 break;
791 }
792 i1++;
793 }
794 SAM("WARNING: failed to adjust saturation: control not found\n");
795 return -ENOENT;
796 }
797 /*****************************************************************************/
adjust_hue(struct easycap * peasycap,int value)798 int adjust_hue(struct easycap *peasycap, int value)
799 {
800 unsigned int mood;
801 int i1, i2, k;
802
803 if (!peasycap) {
804 SAY("ERROR: peasycap is NULL\n");
805 return -EFAULT;
806 }
807 if (!peasycap->pusb_device) {
808 SAM("ERROR: peasycap->pusb_device is NULL\n");
809 return -EFAULT;
810 }
811 i1 = 0;
812 while (0xFFFFFFFF != easycap_control[i1].id) {
813 if (V4L2_CID_HUE == easycap_control[i1].id) {
814 if ((easycap_control[i1].minimum > value) ||
815 (easycap_control[i1].maximum < value))
816 value = easycap_control[i1].default_value;
817
818 if ((easycap_control[i1].minimum <= peasycap->hue) &&
819 (easycap_control[i1].maximum >= peasycap->hue)) {
820 if (peasycap->hue == value) {
821 SAM("unchanged hue at 0x%02X\n", value);
822 return 0;
823 }
824 }
825 peasycap->hue = value;
826 for (k = 0; k < INPUT_MANY; k++) {
827 if (!peasycap->inputset[k].hue_ok)
828 peasycap->inputset[k].hue = peasycap->hue;
829 }
830 if (0 <= peasycap->input && INPUT_MANY > peasycap->input) {
831 peasycap->inputset[peasycap->input].hue = peasycap->hue;
832 peasycap->inputset[peasycap->input].hue_ok = 1;
833 } else
834 JOM(8, "%i=peasycap->input\n", peasycap->input);
835 i2 = peasycap->hue - 128;
836 mood = 0x00FF & ((int) i2);
837 if (write_saa(peasycap->pusb_device, 0x0D, mood)) {
838 SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
839 return -ENOENT;
840 }
841 SAM("adjusting hue to 0x%02X\n", mood);
842 return 0;
843 break;
844 }
845 i1++;
846 }
847 SAM("WARNING: failed to adjust hue: control not found\n");
848 return -ENOENT;
849 }
850 /*****************************************************************************/
adjust_volume(struct easycap * peasycap,int value)851 static int adjust_volume(struct easycap *peasycap, int value)
852 {
853 s8 mood;
854 int i1;
855
856 if (!peasycap) {
857 SAY("ERROR: peasycap is NULL\n");
858 return -EFAULT;
859 }
860 if (!peasycap->pusb_device) {
861 SAM("ERROR: peasycap->pusb_device is NULL\n");
862 return -EFAULT;
863 }
864 i1 = 0;
865 while (0xFFFFFFFF != easycap_control[i1].id) {
866 if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
867 if ((easycap_control[i1].minimum > value) ||
868 (easycap_control[i1].maximum < value))
869 value = easycap_control[i1].default_value;
870
871 if ((easycap_control[i1].minimum <= peasycap->volume) &&
872 (easycap_control[i1].maximum >= peasycap->volume)) {
873 if (peasycap->volume == value) {
874 SAM("unchanged volume at 0x%02X\n", value);
875 return 0;
876 }
877 }
878 peasycap->volume = value;
879 mood = (16 > peasycap->volume) ? 16 :
880 ((31 < peasycap->volume) ? 31 :
881 (s8) peasycap->volume);
882 if (!easycap_audio_gainset(peasycap->pusb_device, mood)) {
883 SAM("WARNING: failed to adjust volume to "
884 "0x%2X\n", mood);
885 return -ENOENT;
886 }
887 SAM("adjusting volume to 0x%02X\n", mood);
888 return 0;
889 }
890 i1++;
891 }
892 SAM("WARNING: failed to adjust volume: control not found\n");
893 return -ENOENT;
894 }
895 /*****************************************************************************/
896 /*---------------------------------------------------------------------------*/
897 /*
898 * AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
899 * usb_set_interface(peasycap->pusb_device,
900 * peasycap->audio_interface,
901 * peasycap->audio_altsetting_off);
902 * HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
903 * -ESHUTDOWN. THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
904 * THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE.
905 */
906 /*---------------------------------------------------------------------------*/
adjust_mute(struct easycap * peasycap,int value)907 static int adjust_mute(struct easycap *peasycap, int value)
908 {
909 int i1;
910
911 if (!peasycap) {
912 SAY("ERROR: peasycap is NULL\n");
913 return -EFAULT;
914 }
915 if (!peasycap->pusb_device) {
916 SAM("ERROR: peasycap->pusb_device is NULL\n");
917 return -EFAULT;
918 }
919 i1 = 0;
920 while (0xFFFFFFFF != easycap_control[i1].id) {
921 if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
922 peasycap->mute = value;
923 switch (peasycap->mute) {
924 case 1: {
925 peasycap->audio_idle = 1;
926 SAM("adjusting mute: %i=peasycap->audio_idle\n",
927 peasycap->audio_idle);
928 return 0;
929 }
930 default: {
931 peasycap->audio_idle = 0;
932 SAM("adjusting mute: %i=peasycap->audio_idle\n",
933 peasycap->audio_idle);
934 return 0;
935 }
936 }
937 break;
938 }
939 i1++;
940 }
941 SAM("WARNING: failed to adjust mute: control not found\n");
942 return -ENOENT;
943 }
944 /*---------------------------------------------------------------------------*/
easycap_unlocked_ioctl(struct file * file,unsigned int cmd,unsigned long arg)945 long easycap_unlocked_ioctl(struct file *file,
946 unsigned int cmd, unsigned long arg)
947 {
948 struct easycap *peasycap;
949 struct usb_device *p;
950 int kd;
951
952 if (!file) {
953 SAY("ERROR: file is NULL\n");
954 return -ERESTARTSYS;
955 }
956 peasycap = file->private_data;
957 if (!peasycap) {
958 SAY("ERROR: peasycap is NULL\n");
959 return -1;
960 }
961 p = peasycap->pusb_device;
962 if (!p) {
963 SAM("ERROR: peasycap->pusb_device is NULL\n");
964 return -EFAULT;
965 }
966 kd = easycap_isdongle(peasycap);
967 if (0 <= kd && DONGLE_MANY > kd) {
968 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
969 SAY("ERROR: cannot lock "
970 "easycapdc60_dongle[%i].mutex_video\n", kd);
971 return -ERESTARTSYS;
972 }
973 JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
974 /*---------------------------------------------------------------------------*/
975 /*
976 * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
977 * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
978 * IF NECESSARY, BAIL OUT.
979 */
980 /*---------------------------------------------------------------------------*/
981 if (kd != easycap_isdongle(peasycap))
982 return -ERESTARTSYS;
983 if (!file) {
984 SAY("ERROR: file is NULL\n");
985 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
986 return -ERESTARTSYS;
987 }
988 peasycap = file->private_data;
989 if (!peasycap) {
990 SAY("ERROR: peasycap is NULL\n");
991 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
992 return -ERESTARTSYS;
993 }
994 if (!peasycap->pusb_device) {
995 SAM("ERROR: peasycap->pusb_device is NULL\n");
996 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
997 return -ERESTARTSYS;
998 }
999 } else {
1000 /*---------------------------------------------------------------------------*/
1001 /*
1002 * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
1003 * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
1004 */
1005 /*---------------------------------------------------------------------------*/
1006 return -ERESTARTSYS;
1007 }
1008 /*---------------------------------------------------------------------------*/
1009 switch (cmd) {
1010 case VIDIOC_QUERYCAP: {
1011 struct v4l2_capability v4l2_capability;
1012 char version[16], *p1, *p2;
1013 int i, rc, k[3];
1014 long lng;
1015
1016 JOM(8, "VIDIOC_QUERYCAP\n");
1017
1018 if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
1019 SAM("ERROR: bad driver version string\n");
1020 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1021 return -EINVAL;
1022 }
1023 strcpy(&version[0], EASYCAP_DRIVER_VERSION);
1024 for (i = 0; i < 3; i++)
1025 k[i] = 0;
1026 p2 = &version[0];
1027 i = 0;
1028 while (*p2) {
1029 p1 = p2;
1030 while (*p2 && ('.' != *p2))
1031 p2++;
1032 if (*p2)
1033 *p2++ = 0;
1034 if (3 > i) {
1035 rc = (int) strict_strtol(p1, 10, &lng);
1036 if (rc) {
1037 SAM("ERROR: %i=strict_strtol(%s,.,,)\n",
1038 rc, p1);
1039 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1040 return -EINVAL;
1041 }
1042 k[i] = (int)lng;
1043 }
1044 i++;
1045 }
1046
1047 memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
1048 strlcpy(&v4l2_capability.driver[0],
1049 "easycap", sizeof(v4l2_capability.driver));
1050
1051 v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE |
1052 V4L2_CAP_STREAMING |
1053 V4L2_CAP_AUDIO |
1054 V4L2_CAP_READWRITE;
1055
1056 v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
1057 JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
1058
1059 strlcpy(&v4l2_capability.card[0],
1060 "EasyCAP DC60", sizeof(v4l2_capability.card));
1061
1062 if (usb_make_path(peasycap->pusb_device,
1063 &v4l2_capability.bus_info[0],
1064 sizeof(v4l2_capability.bus_info)) < 0) {
1065
1066 strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info",
1067 sizeof(v4l2_capability.bus_info));
1068 JOM(8, "%s=v4l2_capability.bus_info\n",
1069 &v4l2_capability.bus_info[0]);
1070 }
1071 if (copy_to_user((void __user *)arg, &v4l2_capability,
1072 sizeof(struct v4l2_capability))) {
1073 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1074 return -EFAULT;
1075 }
1076 break;
1077 }
1078 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1079 case VIDIOC_ENUMINPUT: {
1080 struct v4l2_input v4l2_input;
1081 u32 index;
1082
1083 JOM(8, "VIDIOC_ENUMINPUT\n");
1084
1085 if (copy_from_user(&v4l2_input, (void __user *)arg,
1086 sizeof(struct v4l2_input))) {
1087 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1088 return -EFAULT;
1089 }
1090
1091 index = v4l2_input.index;
1092 memset(&v4l2_input, 0, sizeof(struct v4l2_input));
1093
1094 switch (index) {
1095 case 0: {
1096 v4l2_input.index = index;
1097 strcpy(&v4l2_input.name[0], "CVBS0");
1098 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1099 v4l2_input.audioset = 0x01;
1100 v4l2_input.tuner = 0;
1101 v4l2_input.std = V4L2_STD_PAL |
1102 V4L2_STD_SECAM |
1103 V4L2_STD_NTSC ;
1104 v4l2_input.status = 0;
1105 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1106 break;
1107 }
1108 case 1: {
1109 v4l2_input.index = index;
1110 strcpy(&v4l2_input.name[0], "CVBS1");
1111 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1112 v4l2_input.audioset = 0x01;
1113 v4l2_input.tuner = 0;
1114 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
1115 V4L2_STD_NTSC;
1116 v4l2_input.status = 0;
1117 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1118 break;
1119 }
1120 case 2: {
1121 v4l2_input.index = index;
1122 strcpy(&v4l2_input.name[0], "CVBS2");
1123 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1124 v4l2_input.audioset = 0x01;
1125 v4l2_input.tuner = 0;
1126 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
1127 V4L2_STD_NTSC ;
1128 v4l2_input.status = 0;
1129 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1130 break;
1131 }
1132 case 3: {
1133 v4l2_input.index = index;
1134 strcpy(&v4l2_input.name[0], "CVBS3");
1135 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1136 v4l2_input.audioset = 0x01;
1137 v4l2_input.tuner = 0;
1138 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
1139 V4L2_STD_NTSC ;
1140 v4l2_input.status = 0;
1141 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1142 break;
1143 }
1144 case 4: {
1145 v4l2_input.index = index;
1146 strcpy(&v4l2_input.name[0], "CVBS4");
1147 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1148 v4l2_input.audioset = 0x01;
1149 v4l2_input.tuner = 0;
1150 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
1151 V4L2_STD_NTSC ;
1152 v4l2_input.status = 0;
1153 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1154 break;
1155 }
1156 case 5: {
1157 v4l2_input.index = index;
1158 strcpy(&v4l2_input.name[0], "S-VIDEO");
1159 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1160 v4l2_input.audioset = 0x01;
1161 v4l2_input.tuner = 0;
1162 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM |
1163 V4L2_STD_NTSC ;
1164 v4l2_input.status = 0;
1165 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1166 break;
1167 }
1168 default: {
1169 JOM(8, "%i=index: exhausts inputs\n", index);
1170 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1171 return -EINVAL;
1172 }
1173 }
1174
1175 if (copy_to_user((void __user *)arg, &v4l2_input,
1176 sizeof(struct v4l2_input))) {
1177 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1178 return -EFAULT;
1179 }
1180 break;
1181 }
1182 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1183 case VIDIOC_G_INPUT: {
1184 u32 index;
1185
1186 JOM(8, "VIDIOC_G_INPUT\n");
1187 index = (u32)peasycap->input;
1188 JOM(8, "user is told: %i\n", index);
1189 if (copy_to_user((void __user *)arg, &index, sizeof(u32))) {
1190 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1191 return -EFAULT;
1192 }
1193 break;
1194 }
1195 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1196 case VIDIOC_S_INPUT:
1197 {
1198 u32 index;
1199 int rc;
1200
1201 JOM(8, "VIDIOC_S_INPUT\n");
1202
1203 if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) {
1204 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1205 return -EFAULT;
1206 }
1207
1208 JOM(8, "user requests input %i\n", index);
1209
1210 if ((int)index == peasycap->input) {
1211 SAM("requested input already in effect\n");
1212 break;
1213 }
1214
1215 if ((0 > index) || (INPUT_MANY <= index)) {
1216 JOM(8, "ERROR: bad requested input: %i\n", index);
1217 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1218 return -EINVAL;
1219 }
1220
1221 rc = easycap_newinput(peasycap, (int)index);
1222 if (0 == rc) {
1223 JOM(8, "newinput(.,%i) OK\n", (int)index);
1224 } else {
1225 SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
1226 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1227 return -EFAULT;
1228 }
1229 break;
1230 }
1231 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1232 case VIDIOC_ENUMAUDIO: {
1233 JOM(8, "VIDIOC_ENUMAUDIO\n");
1234 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1235 return -EINVAL;
1236 }
1237 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1238 case VIDIOC_ENUMAUDOUT: {
1239 struct v4l2_audioout v4l2_audioout;
1240
1241 JOM(8, "VIDIOC_ENUMAUDOUT\n");
1242
1243 if (copy_from_user(&v4l2_audioout, (void __user *)arg,
1244 sizeof(struct v4l2_audioout))) {
1245 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1246 return -EFAULT;
1247 }
1248
1249 if (0 != v4l2_audioout.index) {
1250 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1251 return -EINVAL;
1252 }
1253 memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
1254 v4l2_audioout.index = 0;
1255 strcpy(&v4l2_audioout.name[0], "Soundtrack");
1256
1257 if (copy_to_user((void __user *)arg, &v4l2_audioout,
1258 sizeof(struct v4l2_audioout))) {
1259 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1260 return -EFAULT;
1261 }
1262 break;
1263 }
1264 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1265 case VIDIOC_QUERYCTRL: {
1266 int i1;
1267 struct v4l2_queryctrl v4l2_queryctrl;
1268
1269 JOM(8, "VIDIOC_QUERYCTRL\n");
1270
1271 if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg,
1272 sizeof(struct v4l2_queryctrl))) {
1273 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1274 return -EFAULT;
1275 }
1276
1277 i1 = 0;
1278 while (0xFFFFFFFF != easycap_control[i1].id) {
1279 if (easycap_control[i1].id == v4l2_queryctrl.id) {
1280 JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]"
1281 ".name\n", &easycap_control[i1].name[0], i1);
1282 memcpy(&v4l2_queryctrl, &easycap_control[i1],
1283 sizeof(struct v4l2_queryctrl));
1284 break;
1285 }
1286 i1++;
1287 }
1288 if (0xFFFFFFFF == easycap_control[i1].id) {
1289 JOM(8, "%i=index: exhausts controls\n", i1);
1290 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1291 return -EINVAL;
1292 }
1293 if (copy_to_user((void __user *)arg, &v4l2_queryctrl,
1294 sizeof(struct v4l2_queryctrl))) {
1295 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1296 return -EFAULT;
1297 }
1298 break;
1299 }
1300 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1301 case VIDIOC_QUERYMENU: {
1302 JOM(8, "VIDIOC_QUERYMENU unsupported\n");
1303 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1304 return -EINVAL;
1305 }
1306 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1307 case VIDIOC_G_CTRL: {
1308 struct v4l2_control *pv4l2_control;
1309
1310 JOM(8, "VIDIOC_G_CTRL\n");
1311 pv4l2_control = memdup_user((void __user *)arg,
1312 sizeof(struct v4l2_control));
1313 if (IS_ERR(pv4l2_control)) {
1314 SAM("ERROR: copy from user failed\n");
1315 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1316 return PTR_ERR(pv4l2_control);
1317 }
1318
1319 switch (pv4l2_control->id) {
1320 case V4L2_CID_BRIGHTNESS: {
1321 pv4l2_control->value = peasycap->brightness;
1322 JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
1323 break;
1324 }
1325 case V4L2_CID_CONTRAST: {
1326 pv4l2_control->value = peasycap->contrast;
1327 JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
1328 break;
1329 }
1330 case V4L2_CID_SATURATION: {
1331 pv4l2_control->value = peasycap->saturation;
1332 JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
1333 break;
1334 }
1335 case V4L2_CID_HUE: {
1336 pv4l2_control->value = peasycap->hue;
1337 JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
1338 break;
1339 }
1340 case V4L2_CID_AUDIO_VOLUME: {
1341 pv4l2_control->value = peasycap->volume;
1342 JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
1343 break;
1344 }
1345 case V4L2_CID_AUDIO_MUTE: {
1346 if (1 == peasycap->mute)
1347 pv4l2_control->value = true;
1348 else
1349 pv4l2_control->value = false;
1350 JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
1351 break;
1352 }
1353 default: {
1354 SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
1355 pv4l2_control->id);
1356 kfree(pv4l2_control);
1357 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1358 return -EINVAL;
1359 }
1360 }
1361 if (copy_to_user((void __user *)arg, pv4l2_control,
1362 sizeof(struct v4l2_control))) {
1363 kfree(pv4l2_control);
1364 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1365 return -EFAULT;
1366 }
1367 kfree(pv4l2_control);
1368 break;
1369 }
1370 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1371 case VIDIOC_S_CTRL: {
1372 struct v4l2_control v4l2_control;
1373
1374 JOM(8, "VIDIOC_S_CTRL\n");
1375
1376 if (0 != copy_from_user(&v4l2_control, (void __user *)arg,
1377 sizeof(struct v4l2_control))) {
1378 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1379 return -EFAULT;
1380 }
1381
1382 switch (v4l2_control.id) {
1383 case V4L2_CID_BRIGHTNESS: {
1384 JOM(8, "user requests brightness %i\n", v4l2_control.value);
1385 if (0 != adjust_brightness(peasycap, v4l2_control.value))
1386 ;
1387 break;
1388 }
1389 case V4L2_CID_CONTRAST: {
1390 JOM(8, "user requests contrast %i\n", v4l2_control.value);
1391 if (0 != adjust_contrast(peasycap, v4l2_control.value))
1392 ;
1393 break;
1394 }
1395 case V4L2_CID_SATURATION: {
1396 JOM(8, "user requests saturation %i\n", v4l2_control.value);
1397 if (0 != adjust_saturation(peasycap, v4l2_control.value))
1398 ;
1399 break;
1400 }
1401 case V4L2_CID_HUE: {
1402 JOM(8, "user requests hue %i\n", v4l2_control.value);
1403 if (0 != adjust_hue(peasycap, v4l2_control.value))
1404 ;
1405 break;
1406 }
1407 case V4L2_CID_AUDIO_VOLUME: {
1408 JOM(8, "user requests volume %i\n", v4l2_control.value);
1409 if (0 != adjust_volume(peasycap, v4l2_control.value))
1410 ;
1411 break;
1412 }
1413 case V4L2_CID_AUDIO_MUTE: {
1414 int mute;
1415
1416 JOM(8, "user requests mute %i\n", v4l2_control.value);
1417 if (v4l2_control.value)
1418 mute = 1;
1419 else
1420 mute = 0;
1421
1422 if (0 != adjust_mute(peasycap, mute))
1423 SAM("WARNING: failed to adjust mute to %i\n", mute);
1424 break;
1425 }
1426 default: {
1427 SAM("ERROR: unknown V4L2 control: 0x%08X=id\n",
1428 v4l2_control.id);
1429 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1430 return -EINVAL;
1431 }
1432 }
1433 break;
1434 }
1435 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1436 case VIDIOC_S_EXT_CTRLS: {
1437 JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
1438 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1439 return -EINVAL;
1440 }
1441 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1442 case VIDIOC_ENUM_FMT: {
1443 u32 index;
1444 struct v4l2_fmtdesc v4l2_fmtdesc;
1445
1446 JOM(8, "VIDIOC_ENUM_FMT\n");
1447
1448 if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg,
1449 sizeof(struct v4l2_fmtdesc))) {
1450 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1451 return -EFAULT;
1452 }
1453
1454 index = v4l2_fmtdesc.index;
1455 memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
1456
1457 v4l2_fmtdesc.index = index;
1458 v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1459
1460 switch (index) {
1461 case 0: {
1462 v4l2_fmtdesc.flags = 0;
1463 strcpy(&v4l2_fmtdesc.description[0], "uyvy");
1464 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
1465 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1466 break;
1467 }
1468 case 1: {
1469 v4l2_fmtdesc.flags = 0;
1470 strcpy(&v4l2_fmtdesc.description[0], "yuy2");
1471 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
1472 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1473 break;
1474 }
1475 case 2: {
1476 v4l2_fmtdesc.flags = 0;
1477 strcpy(&v4l2_fmtdesc.description[0], "rgb24");
1478 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
1479 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1480 break;
1481 }
1482 case 3: {
1483 v4l2_fmtdesc.flags = 0;
1484 strcpy(&v4l2_fmtdesc.description[0], "rgb32");
1485 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
1486 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1487 break;
1488 }
1489 case 4: {
1490 v4l2_fmtdesc.flags = 0;
1491 strcpy(&v4l2_fmtdesc.description[0], "bgr24");
1492 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
1493 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1494 break;
1495 }
1496 case 5: {
1497 v4l2_fmtdesc.flags = 0;
1498 strcpy(&v4l2_fmtdesc.description[0], "bgr32");
1499 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
1500 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1501 break;
1502 }
1503 default: {
1504 JOM(8, "%i=index: exhausts formats\n", index);
1505 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1506 return -EINVAL;
1507 }
1508 }
1509 if (copy_to_user((void __user *)arg, &v4l2_fmtdesc,
1510 sizeof(struct v4l2_fmtdesc))) {
1511 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1512 return -EFAULT;
1513 }
1514 break;
1515 }
1516 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1517 /*
1518 * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
1519 * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
1520 */
1521 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1522 case VIDIOC_ENUM_FRAMESIZES: {
1523 u32 index;
1524 struct v4l2_frmsizeenum v4l2_frmsizeenum;
1525
1526 JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
1527
1528 if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg,
1529 sizeof(struct v4l2_frmsizeenum))) {
1530 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1531 return -EFAULT;
1532 }
1533
1534 index = v4l2_frmsizeenum.index;
1535
1536 v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE;
1537
1538 if (peasycap->ntsc) {
1539 switch (index) {
1540 case 0: {
1541 v4l2_frmsizeenum.discrete.width = 640;
1542 v4l2_frmsizeenum.discrete.height = 480;
1543 JOM(8, "%i=index: %ix%i\n", index,
1544 (int)(v4l2_frmsizeenum.
1545 discrete.width),
1546 (int)(v4l2_frmsizeenum.
1547 discrete.height));
1548 break;
1549 }
1550 case 1: {
1551 v4l2_frmsizeenum.discrete.width = 320;
1552 v4l2_frmsizeenum.discrete.height = 240;
1553 JOM(8, "%i=index: %ix%i\n", index,
1554 (int)(v4l2_frmsizeenum.
1555 discrete.width),
1556 (int)(v4l2_frmsizeenum.
1557 discrete.height));
1558 break;
1559 }
1560 case 2: {
1561 v4l2_frmsizeenum.discrete.width = 720;
1562 v4l2_frmsizeenum.discrete.height = 480;
1563 JOM(8, "%i=index: %ix%i\n", index,
1564 (int)(v4l2_frmsizeenum.
1565 discrete.width),
1566 (int)(v4l2_frmsizeenum.
1567 discrete.height));
1568 break;
1569 }
1570 case 3: {
1571 v4l2_frmsizeenum.discrete.width = 360;
1572 v4l2_frmsizeenum.discrete.height = 240;
1573 JOM(8, "%i=index: %ix%i\n", index,
1574 (int)(v4l2_frmsizeenum.
1575 discrete.width),
1576 (int)(v4l2_frmsizeenum.
1577 discrete.height));
1578 break;
1579 }
1580 default: {
1581 JOM(8, "%i=index: exhausts framesizes\n", index);
1582 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1583 return -EINVAL;
1584 }
1585 }
1586 } else {
1587 switch (index) {
1588 case 0: {
1589 v4l2_frmsizeenum.discrete.width = 640;
1590 v4l2_frmsizeenum.discrete.height = 480;
1591 JOM(8, "%i=index: %ix%i\n", index,
1592 (int)(v4l2_frmsizeenum.
1593 discrete.width),
1594 (int)(v4l2_frmsizeenum.
1595 discrete.height));
1596 break;
1597 }
1598 case 1: {
1599 v4l2_frmsizeenum.discrete.width = 320;
1600 v4l2_frmsizeenum.discrete.height = 240;
1601 JOM(8, "%i=index: %ix%i\n", index,
1602 (int)(v4l2_frmsizeenum.
1603 discrete.width),
1604 (int)(v4l2_frmsizeenum.
1605 discrete.height));
1606 break;
1607 }
1608 case 2: {
1609 v4l2_frmsizeenum.discrete.width = 704;
1610 v4l2_frmsizeenum.discrete.height = 576;
1611 JOM(8, "%i=index: %ix%i\n", index,
1612 (int)(v4l2_frmsizeenum.
1613 discrete.width),
1614 (int)(v4l2_frmsizeenum.
1615 discrete.height));
1616 break;
1617 }
1618 case 3: {
1619 v4l2_frmsizeenum.discrete.width = 720;
1620 v4l2_frmsizeenum.discrete.height = 576;
1621 JOM(8, "%i=index: %ix%i\n", index,
1622 (int)(v4l2_frmsizeenum.
1623 discrete.width),
1624 (int)(v4l2_frmsizeenum.
1625 discrete.height));
1626 break;
1627 }
1628 case 4: {
1629 v4l2_frmsizeenum.discrete.width = 360;
1630 v4l2_frmsizeenum.discrete.height = 288;
1631 JOM(8, "%i=index: %ix%i\n", index,
1632 (int)(v4l2_frmsizeenum.
1633 discrete.width),
1634 (int)(v4l2_frmsizeenum.
1635 discrete.height));
1636 break;
1637 }
1638 default: {
1639 JOM(8, "%i=index: exhausts framesizes\n", index);
1640 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1641 return -EINVAL;
1642 }
1643 }
1644 }
1645 if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum,
1646 sizeof(struct v4l2_frmsizeenum))) {
1647 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1648 return -EFAULT;
1649 }
1650 break;
1651 }
1652 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1653 /*
1654 * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
1655 * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
1656 */
1657 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1658 case VIDIOC_ENUM_FRAMEINTERVALS: {
1659 u32 index;
1660 int denominator;
1661 struct v4l2_frmivalenum v4l2_frmivalenum;
1662
1663 JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
1664
1665 if (peasycap->fps)
1666 denominator = peasycap->fps;
1667 else {
1668 if (peasycap->ntsc)
1669 denominator = 30;
1670 else
1671 denominator = 25;
1672 }
1673
1674 if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg,
1675 sizeof(struct v4l2_frmivalenum))) {
1676 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1677 return -EFAULT;
1678 }
1679
1680 index = v4l2_frmivalenum.index;
1681
1682 v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE;
1683
1684 switch (index) {
1685 case 0: {
1686 v4l2_frmivalenum.discrete.numerator = 1;
1687 v4l2_frmivalenum.discrete.denominator = denominator;
1688 JOM(8, "%i=index: %i/%i\n", index,
1689 (int)(v4l2_frmivalenum.discrete.numerator),
1690 (int)(v4l2_frmivalenum.discrete.denominator));
1691 break;
1692 }
1693 case 1: {
1694 v4l2_frmivalenum.discrete.numerator = 1;
1695 v4l2_frmivalenum.discrete.denominator = denominator/5;
1696 JOM(8, "%i=index: %i/%i\n", index,
1697 (int)(v4l2_frmivalenum.discrete.numerator),
1698 (int)(v4l2_frmivalenum.discrete.denominator));
1699 break;
1700 }
1701 default: {
1702 JOM(8, "%i=index: exhausts frameintervals\n", index);
1703 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1704 return -EINVAL;
1705 }
1706 }
1707 if (copy_to_user((void __user *)arg, &v4l2_frmivalenum,
1708 sizeof(struct v4l2_frmivalenum))) {
1709 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1710 return -EFAULT;
1711 }
1712 break;
1713 }
1714 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1715 case VIDIOC_G_FMT: {
1716 struct v4l2_format *pv4l2_format;
1717 struct v4l2_pix_format *pv4l2_pix_format;
1718
1719 JOM(8, "VIDIOC_G_FMT\n");
1720 pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
1721 if (!pv4l2_format) {
1722 SAM("ERROR: out of memory\n");
1723 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1724 return -ENOMEM;
1725 }
1726 pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
1727 if (!pv4l2_pix_format) {
1728 SAM("ERROR: out of memory\n");
1729 kfree(pv4l2_format);
1730 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1731 return -ENOMEM;
1732 }
1733 if (0 != copy_from_user(pv4l2_format, (void __user *)arg,
1734 sizeof(struct v4l2_format))) {
1735 kfree(pv4l2_format);
1736 kfree(pv4l2_pix_format);
1737 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1738 return -EFAULT;
1739 }
1740
1741 if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1742 kfree(pv4l2_format);
1743 kfree(pv4l2_pix_format);
1744 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1745 return -EINVAL;
1746 }
1747
1748 memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
1749 pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1750 memcpy(&pv4l2_format->fmt.pix,
1751 &easycap_format[peasycap->format_offset]
1752 .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
1753 JOM(8, "user is told: %s\n",
1754 &easycap_format[peasycap->format_offset].name[0]);
1755
1756 if (copy_to_user((void __user *)arg, pv4l2_format,
1757 sizeof(struct v4l2_format))) {
1758 kfree(pv4l2_format);
1759 kfree(pv4l2_pix_format);
1760 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1761 return -EFAULT;
1762 }
1763 kfree(pv4l2_format);
1764 kfree(pv4l2_pix_format);
1765 break;
1766 }
1767 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1768 case VIDIOC_TRY_FMT:
1769 case VIDIOC_S_FMT: {
1770 struct v4l2_format v4l2_format;
1771 struct v4l2_pix_format v4l2_pix_format;
1772 bool try;
1773 int best_format;
1774
1775 if (VIDIOC_TRY_FMT == cmd) {
1776 JOM(8, "VIDIOC_TRY_FMT\n");
1777 try = true;
1778 } else {
1779 JOM(8, "VIDIOC_S_FMT\n");
1780 try = false;
1781 }
1782
1783 if (0 != copy_from_user(&v4l2_format, (void __user *)arg,
1784 sizeof(struct v4l2_format))) {
1785 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1786 return -EFAULT;
1787 }
1788
1789 best_format = adjust_format(peasycap,
1790 v4l2_format.fmt.pix.width,
1791 v4l2_format.fmt.pix.height,
1792 v4l2_format.fmt.pix.pixelformat,
1793 v4l2_format.fmt.pix.field,
1794 try);
1795 if (0 > best_format) {
1796 if (-EBUSY == best_format) {
1797 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1798 return -EBUSY;
1799 }
1800 JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
1801 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1802 return -ENOENT;
1803 }
1804 /*...........................................................................*/
1805 memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
1806 v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1807
1808 memcpy(&(v4l2_format.fmt.pix),
1809 &(easycap_format[best_format].v4l2_format.fmt.pix),
1810 sizeof(v4l2_pix_format));
1811 JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
1812
1813 if (copy_to_user((void __user *)arg, &v4l2_format,
1814 sizeof(struct v4l2_format))) {
1815 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1816 return -EFAULT;
1817 }
1818 break;
1819 }
1820 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1821 case VIDIOC_CROPCAP: {
1822 struct v4l2_cropcap v4l2_cropcap;
1823
1824 JOM(8, "VIDIOC_CROPCAP\n");
1825
1826 if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg,
1827 sizeof(struct v4l2_cropcap))) {
1828 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1829 return -EFAULT;
1830 }
1831
1832 if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1833 JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
1834
1835 memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
1836 v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1837 v4l2_cropcap.bounds.left = 0;
1838 v4l2_cropcap.bounds.top = 0;
1839 v4l2_cropcap.bounds.width = peasycap->width;
1840 v4l2_cropcap.bounds.height = peasycap->height;
1841 v4l2_cropcap.defrect.left = 0;
1842 v4l2_cropcap.defrect.top = 0;
1843 v4l2_cropcap.defrect.width = peasycap->width;
1844 v4l2_cropcap.defrect.height = peasycap->height;
1845 v4l2_cropcap.pixelaspect.numerator = 1;
1846 v4l2_cropcap.pixelaspect.denominator = 1;
1847
1848 JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
1849
1850 if (copy_to_user((void __user *)arg, &v4l2_cropcap,
1851 sizeof(struct v4l2_cropcap))) {
1852 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1853 return -EFAULT;
1854 }
1855 break;
1856 }
1857 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1858 case VIDIOC_G_CROP:
1859 case VIDIOC_S_CROP: {
1860 JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
1861 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1862 return -EINVAL;
1863 }
1864 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1865 case VIDIOC_QUERYSTD: {
1866 JOM(8, "VIDIOC_QUERYSTD: "
1867 "EasyCAP is incapable of detecting standard\n");
1868 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1869 return -EINVAL;
1870 break;
1871 }
1872 /*-------------------------------------------------------------------*/
1873 /*
1874 * THE MANIPULATIONS INVOLVING last0,last1,last2,last3
1875 * CONSTITUTE A WORKAROUND * FOR WHAT APPEARS TO BE
1876 * A BUG IN 64-BIT mplayer.
1877 * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
1878 */
1879 /*------------------------------------------------------------------*/
1880 case VIDIOC_ENUMSTD: {
1881 int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
1882 struct v4l2_standard v4l2_standard;
1883 u32 index;
1884 struct easycap_standard const *peasycap_standard;
1885
1886 JOM(8, "VIDIOC_ENUMSTD\n");
1887
1888 if (0 != copy_from_user(&v4l2_standard, (void __user *)arg,
1889 sizeof(struct v4l2_standard))) {
1890 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1891 return -EFAULT;
1892 }
1893 index = v4l2_standard.index;
1894
1895 last3 = last2;
1896 last2 = last1;
1897 last1 = last0;
1898 last0 = index;
1899 if ((index == last3) && (index == last2) &&
1900 (index == last1) && (index == last0)) {
1901 index++;
1902 last3 = last2;
1903 last2 = last1;
1904 last1 = last0;
1905 last0 = index;
1906 }
1907
1908 memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
1909
1910 peasycap_standard = &easycap_standard[0];
1911 while (0xFFFF != peasycap_standard->mask) {
1912 if ((int)(peasycap_standard - &easycap_standard[0]) == index)
1913 break;
1914 peasycap_standard++;
1915 }
1916 if (0xFFFF == peasycap_standard->mask) {
1917 JOM(8, "%i=index: exhausts standards\n", index);
1918 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1919 return -EINVAL;
1920 }
1921 JOM(8, "%i=index: %s\n", index,
1922 &(peasycap_standard->v4l2_standard.name[0]));
1923 memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard),
1924 sizeof(struct v4l2_standard));
1925
1926 v4l2_standard.index = index;
1927
1928 if (copy_to_user((void __user *)arg, &v4l2_standard,
1929 sizeof(struct v4l2_standard))) {
1930 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1931 return -EFAULT;
1932 }
1933 break;
1934 }
1935 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1936 case VIDIOC_G_STD: {
1937 v4l2_std_id std_id;
1938 struct easycap_standard const *peasycap_standard;
1939
1940 JOM(8, "VIDIOC_G_STD\n");
1941
1942 if (0 > peasycap->standard_offset) {
1943 JOM(8, "%i=peasycap->standard_offset\n",
1944 peasycap->standard_offset);
1945 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1946 return -EBUSY;
1947 }
1948
1949 if (0 != copy_from_user(&std_id, (void __user *)arg,
1950 sizeof(v4l2_std_id))) {
1951 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1952 return -EFAULT;
1953 }
1954
1955 peasycap_standard = &easycap_standard[peasycap->standard_offset];
1956 std_id = peasycap_standard->v4l2_standard.id;
1957
1958 JOM(8, "user is told: %s\n",
1959 &peasycap_standard->v4l2_standard.name[0]);
1960
1961 if (copy_to_user((void __user *)arg, &std_id,
1962 sizeof(v4l2_std_id))) {
1963 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1964 return -EFAULT;
1965 }
1966 break;
1967 }
1968 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1969 case VIDIOC_S_STD: {
1970 v4l2_std_id std_id;
1971 int rc;
1972
1973 JOM(8, "VIDIOC_S_STD\n");
1974
1975 if (0 != copy_from_user(&std_id, (void __user *)arg,
1976 sizeof(v4l2_std_id))) {
1977 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1978 return -EFAULT;
1979 }
1980
1981 JOM(8, "User requests standard: 0x%08X%08X\n",
1982 (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32),
1983 (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
1984
1985 rc = adjust_standard(peasycap, std_id);
1986 if (0 > rc) {
1987 JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
1988 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1989 return -ENOENT;
1990 }
1991 break;
1992 }
1993 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1994 case VIDIOC_REQBUFS: {
1995 int nbuffers;
1996 struct v4l2_requestbuffers v4l2_requestbuffers;
1997
1998 JOM(8, "VIDIOC_REQBUFS\n");
1999
2000 if (0 != copy_from_user(&v4l2_requestbuffers,
2001 (void __user *)arg,
2002 sizeof(struct v4l2_requestbuffers))) {
2003 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2004 return -EFAULT;
2005 }
2006
2007 if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2008 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2009 return -EINVAL;
2010 }
2011 if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
2012 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2013 return -EINVAL;
2014 }
2015 nbuffers = v4l2_requestbuffers.count;
2016 JOM(8, " User requests %i buffers ...\n", nbuffers);
2017 if (nbuffers < 2)
2018 nbuffers = 2;
2019 if (nbuffers > FRAME_BUFFER_MANY)
2020 nbuffers = FRAME_BUFFER_MANY;
2021 if (v4l2_requestbuffers.count == nbuffers) {
2022 JOM(8, " ... agree to %i buffers\n",
2023 nbuffers);
2024 } else {
2025 JOM(8, " ... insist on %i buffers\n",
2026 nbuffers);
2027 v4l2_requestbuffers.count = nbuffers;
2028 }
2029 peasycap->frame_buffer_many = nbuffers;
2030
2031 if (copy_to_user((void __user *)arg, &v4l2_requestbuffers,
2032 sizeof(struct v4l2_requestbuffers))) {
2033 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2034 return -EFAULT;
2035 }
2036 break;
2037 }
2038 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2039 case VIDIOC_QUERYBUF: {
2040 u32 index;
2041 struct v4l2_buffer v4l2_buffer;
2042
2043 JOM(8, "VIDIOC_QUERYBUF\n");
2044
2045 if (peasycap->video_eof) {
2046 JOM(8, "returning -EIO because %i=video_eof\n",
2047 peasycap->video_eof);
2048 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2049 return -EIO;
2050 }
2051
2052 if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
2053 sizeof(struct v4l2_buffer))) {
2054 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2055 return -EFAULT;
2056 }
2057
2058 if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2059 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2060 return -EINVAL;
2061 }
2062 index = v4l2_buffer.index;
2063 if (index < 0 || index >= peasycap->frame_buffer_many)
2064 return -EINVAL;
2065 memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
2066 v4l2_buffer.index = index;
2067 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2068 v4l2_buffer.bytesused = peasycap->frame_buffer_used;
2069 v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED |
2070 peasycap->done[index] |
2071 peasycap->queued[index];
2072 v4l2_buffer.field = V4L2_FIELD_NONE;
2073 v4l2_buffer.memory = V4L2_MEMORY_MMAP;
2074 v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
2075 v4l2_buffer.length = FRAME_BUFFER_SIZE;
2076
2077 JOM(16, " %10i=index\n", v4l2_buffer.index);
2078 JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
2079 JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
2080 JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
2081 JOM(16, " %10i=field\n", v4l2_buffer.field);
2082 JOM(16, " %10li=timestamp.tv_usec\n",
2083 (long)v4l2_buffer.timestamp.tv_usec);
2084 JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
2085 JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
2086 JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
2087 JOM(16, " %10i=length\n", v4l2_buffer.length);
2088
2089 if (copy_to_user((void __user *)arg, &v4l2_buffer,
2090 sizeof(struct v4l2_buffer))) {
2091 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2092 return -EFAULT;
2093 }
2094 break;
2095 }
2096 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2097 case VIDIOC_QBUF: {
2098 struct v4l2_buffer v4l2_buffer;
2099
2100 JOM(8, "VIDIOC_QBUF\n");
2101
2102 if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg,
2103 sizeof(struct v4l2_buffer))) {
2104 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2105 return -EFAULT;
2106 }
2107
2108 if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2109 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2110 return -EINVAL;
2111 }
2112 if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
2113 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2114 return -EINVAL;
2115 }
2116 if (v4l2_buffer.index < 0 ||
2117 v4l2_buffer.index >= peasycap->frame_buffer_many) {
2118 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2119 return -EINVAL;
2120 }
2121 v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
2122
2123 peasycap->done[v4l2_buffer.index] = 0;
2124 peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
2125
2126 if (copy_to_user((void __user *)arg, &v4l2_buffer,
2127 sizeof(struct v4l2_buffer))) {
2128 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2129 return -EFAULT;
2130 }
2131
2132 JOM(8, "..... user queueing frame buffer %i\n",
2133 (int)v4l2_buffer.index);
2134
2135 peasycap->frame_lock = 0;
2136
2137 break;
2138 }
2139 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2140 case VIDIOC_DQBUF:
2141 {
2142 struct timeval timeval, timeval2;
2143 int i, j;
2144 struct v4l2_buffer v4l2_buffer;
2145 int rcdq;
2146 u16 input;
2147
2148 JOM(8, "VIDIOC_DQBUF\n");
2149
2150 if ((peasycap->video_idle) || (peasycap->video_eof)) {
2151 JOM(8, "returning -EIO because "
2152 "%i=video_idle %i=video_eof\n",
2153 peasycap->video_idle, peasycap->video_eof);
2154 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2155 return -EIO;
2156 }
2157
2158 if (copy_from_user(&v4l2_buffer, (void __user *)arg,
2159 sizeof(struct v4l2_buffer))) {
2160 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2161 return -EFAULT;
2162 }
2163
2164 if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2165 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2166 return -EINVAL;
2167 }
2168
2169 if (peasycap->offerfields) {
2170 /*---------------------------------------------------*/
2171 /*
2172 * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
2173 * V4L2_FIELD_BOTTOM
2174 */
2175 /*---------------------------------------------------*/
2176 if (V4L2_FIELD_TOP == v4l2_buffer.field)
2177 JOM(8, "user wants V4L2_FIELD_TOP\n");
2178 else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
2179 JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
2180 else if (V4L2_FIELD_ANY == v4l2_buffer.field)
2181 JOM(8, "user wants V4L2_FIELD_ANY\n");
2182 else
2183 JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n",
2184 v4l2_buffer.field);
2185 }
2186
2187 if (!peasycap->video_isoc_streaming) {
2188 JOM(16, "returning -EIO because video urbs not streaming\n");
2189 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2190 return -EIO;
2191 }
2192 /*-------------------------------------------------------------------*/
2193 /*
2194 * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(),
2195 * AS DETERMINED BY FINDING
2196 * THE FLAG peasycap->polled SET, THERE MUST BE
2197 * NO FURTHER WAIT HERE. IN THIS
2198 * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
2199 */
2200 /*-------------------------------------------------------------------*/
2201
2202 if (!peasycap->polled) {
2203 do {
2204 rcdq = easycap_video_dqbuf(peasycap, 0);
2205 if (-EIO == rcdq) {
2206 JOM(8, "returning -EIO because "
2207 "dqbuf() returned -EIO\n");
2208 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2209 return -EIO;
2210 }
2211 } while (0 != rcdq);
2212 } else {
2213 if (peasycap->video_eof) {
2214 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2215 return -EIO;
2216 }
2217 }
2218 if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
2219 JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n",
2220 peasycap->done[peasycap->frame_read]);
2221 }
2222 peasycap->polled = 0;
2223
2224 if (!(peasycap->isequence % 10)) {
2225 for (i = 0; i < 179; i++)
2226 peasycap->merit[i] = peasycap->merit[i+1];
2227 peasycap->merit[179] = merit_saa(peasycap->pusb_device);
2228 j = 0;
2229 for (i = 0; i < 180; i++)
2230 j += peasycap->merit[i];
2231 if (90 < j) {
2232 SAM("easycap driver shutting down "
2233 "on condition blue\n");
2234 peasycap->video_eof = 1;
2235 peasycap->audio_eof = 1;
2236 }
2237 }
2238
2239 v4l2_buffer.index = peasycap->frame_read;
2240 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2241 v4l2_buffer.bytesused = peasycap->frame_buffer_used;
2242 v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
2243 if (peasycap->offerfields)
2244 v4l2_buffer.field = V4L2_FIELD_BOTTOM;
2245 else
2246 v4l2_buffer.field = V4L2_FIELD_NONE;
2247 do_gettimeofday(&timeval);
2248 timeval2 = timeval;
2249
2250 v4l2_buffer.timestamp = timeval2;
2251 v4l2_buffer.sequence = peasycap->isequence++;
2252 v4l2_buffer.memory = V4L2_MEMORY_MMAP;
2253 v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
2254 v4l2_buffer.length = FRAME_BUFFER_SIZE;
2255
2256 JOM(16, " %10i=index\n", v4l2_buffer.index);
2257 JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
2258 JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
2259 JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
2260 JOM(16, " %10i=field\n", v4l2_buffer.field);
2261 JOM(16, " %10li=timestamp.tv_sec\n",
2262 (long)v4l2_buffer.timestamp.tv_sec);
2263 JOM(16, " %10li=timestamp.tv_usec\n",
2264 (long)v4l2_buffer.timestamp.tv_usec);
2265 JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
2266 JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
2267 JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
2268 JOM(16, " %10i=length\n", v4l2_buffer.length);
2269
2270 if (copy_to_user((void __user *)arg, &v4l2_buffer,
2271 sizeof(struct v4l2_buffer))) {
2272 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2273 return -EFAULT;
2274 }
2275
2276 input = peasycap->frame_buffer[peasycap->frame_read][0].input;
2277 if (0x08 & input) {
2278 JOM(8, "user is offered frame buffer %i, input %i\n",
2279 peasycap->frame_read, (0x07 & input));
2280 } else {
2281 JOM(8, "user is offered frame buffer %i\n",
2282 peasycap->frame_read);
2283 }
2284 peasycap->frame_lock = 1;
2285 JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
2286 if (peasycap->frame_read == peasycap->frame_fill) {
2287 if (peasycap->frame_lock) {
2288 JOM(8, "WORRY: filling frame buffer "
2289 "while offered to user\n");
2290 }
2291 }
2292 break;
2293 }
2294 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2295 case VIDIOC_STREAMON: {
2296 int i;
2297
2298 JOM(8, "VIDIOC_STREAMON\n");
2299
2300 peasycap->isequence = 0;
2301 for (i = 0; i < 180; i++)
2302 peasycap->merit[i] = 0;
2303 if (!peasycap->pusb_device) {
2304 SAM("ERROR: peasycap->pusb_device is NULL\n");
2305 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2306 return -EFAULT;
2307 }
2308 easycap_video_submit_urbs(peasycap);
2309 peasycap->video_idle = 0;
2310 peasycap->audio_idle = 0;
2311 peasycap->video_eof = 0;
2312 peasycap->audio_eof = 0;
2313 break;
2314 }
2315 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2316 case VIDIOC_STREAMOFF: {
2317 JOM(8, "VIDIOC_STREAMOFF\n");
2318
2319 if (!peasycap->pusb_device) {
2320 SAM("ERROR: peasycap->pusb_device is NULL\n");
2321 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2322 return -EFAULT;
2323 }
2324
2325 peasycap->video_idle = 1;
2326 peasycap->audio_idle = 1;
2327 /*---------------------------------------------------------------------------*/
2328 /*
2329 * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
2330 * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
2331 */
2332 /*---------------------------------------------------------------------------*/
2333 JOM(8, "calling wake_up on wq_video and wq_audio\n");
2334 wake_up_interruptible(&(peasycap->wq_video));
2335 if (peasycap->psubstream)
2336 snd_pcm_period_elapsed(peasycap->psubstream);
2337 break;
2338 }
2339 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2340 case VIDIOC_G_PARM: {
2341 struct v4l2_streamparm *pv4l2_streamparm;
2342
2343 JOM(8, "VIDIOC_G_PARM\n");
2344 pv4l2_streamparm = memdup_user((void __user *)arg,
2345 sizeof(struct v4l2_streamparm));
2346 if (IS_ERR(pv4l2_streamparm)) {
2347 SAM("ERROR: copy from user failed\n");
2348 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2349 return PTR_ERR(pv4l2_streamparm);
2350 }
2351
2352 if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2353 kfree(pv4l2_streamparm);
2354 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2355 return -EINVAL;
2356 }
2357 pv4l2_streamparm->parm.capture.capability = 0;
2358 pv4l2_streamparm->parm.capture.capturemode = 0;
2359 pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
2360
2361 if (peasycap->fps) {
2362 pv4l2_streamparm->parm.capture.timeperframe.
2363 denominator = peasycap->fps;
2364 } else {
2365 if (peasycap->ntsc) {
2366 pv4l2_streamparm->parm.capture.timeperframe.
2367 denominator = 30;
2368 } else {
2369 pv4l2_streamparm->parm.capture.timeperframe.
2370 denominator = 25;
2371 }
2372 }
2373
2374 pv4l2_streamparm->parm.capture.readbuffers =
2375 peasycap->frame_buffer_many;
2376 pv4l2_streamparm->parm.capture.extendedmode = 0;
2377 if (copy_to_user((void __user *)arg,
2378 pv4l2_streamparm,
2379 sizeof(struct v4l2_streamparm))) {
2380 kfree(pv4l2_streamparm);
2381 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2382 return -EFAULT;
2383 }
2384 kfree(pv4l2_streamparm);
2385 break;
2386 }
2387 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2388 case VIDIOC_S_PARM: {
2389 JOM(8, "VIDIOC_S_PARM unsupported\n");
2390 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2391 return -EINVAL;
2392 }
2393 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2394 case VIDIOC_G_AUDIO: {
2395 JOM(8, "VIDIOC_G_AUDIO unsupported\n");
2396 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2397 return -EINVAL;
2398 }
2399 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2400 case VIDIOC_S_AUDIO: {
2401 JOM(8, "VIDIOC_S_AUDIO unsupported\n");
2402 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2403 return -EINVAL;
2404 }
2405 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2406 case VIDIOC_S_TUNER: {
2407 JOM(8, "VIDIOC_S_TUNER unsupported\n");
2408 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2409 return -EINVAL;
2410 }
2411 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2412 case VIDIOC_G_FBUF:
2413 case VIDIOC_S_FBUF:
2414 case VIDIOC_OVERLAY: {
2415 JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
2416 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2417 return -EINVAL;
2418 }
2419 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2420 case VIDIOC_G_TUNER: {
2421 JOM(8, "VIDIOC_G_TUNER unsupported\n");
2422 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2423 return -EINVAL;
2424 }
2425 case VIDIOC_G_FREQUENCY:
2426 case VIDIOC_S_FREQUENCY: {
2427 JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
2428 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2429 return -EINVAL;
2430 }
2431 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2432 default: {
2433 JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
2434 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2435 return -ENOIOCTLCMD;
2436 }
2437 }
2438 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2439 JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
2440 return 0;
2441 }
2442 /*****************************************************************************/
2443