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