staging: easycap: add ALSA support
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / easycap / easycap_ioctl.c
blob20d30334233ed65517cb2bc8608cbdc7c05251c3
1 /******************************************************************************
2 * *
3 * easycap_ioctl.c *
4 * *
5 ******************************************************************************/
6 /*
8 * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
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.
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.
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
26 /*****************************************************************************/
28 #include <linux/smp_lock.h>
29 #include "easycap.h"
30 #include "easycap_ioctl.h"
32 /*--------------------------------------------------------------------------*/
34 * UNLESS THERE IS A PREMATURE ERROR RETURN THIS ROUTINE UPDATES THE
35 * FOLLOWING:
36 * peasycap->standard_offset
37 * peasycap->inputset[peasycap->input].standard_offset
38 * peasycap->fps
39 * peasycap->usec
40 * peasycap->tolerate
41 * peasycap->skip
43 /*---------------------------------------------------------------------------*/
44 int adjust_standard(struct easycap *peasycap, v4l2_std_id std_id)
46 struct easycap_standard const *peasycap_standard;
47 __u16 reg, set;
48 int ir, rc, need, k;
49 unsigned int itwas, isnow;
50 bool resubmit;
52 if (NULL == peasycap) {
53 SAY("ERROR: peasycap is NULL\n");
54 return -EFAULT;
56 if ((struct usb_device *)NULL == peasycap->pusb_device) {
57 SAM("ERROR: peasycap->pusb_device is NULL\n");
58 return -EFAULT;
60 peasycap_standard = &easycap_standard[0];
61 while (0xFFFF != peasycap_standard->mask) {
62 if (std_id == peasycap_standard->v4l2_standard.id)
63 break;
64 peasycap_standard++;
66 if (0xFFFF == peasycap_standard->mask) {
67 peasycap_standard = &easycap_standard[0];
68 while (0xFFFF != peasycap_standard->mask) {
69 if (std_id & peasycap_standard->v4l2_standard.id)
70 break;
71 peasycap_standard++;
74 if (0xFFFF == peasycap_standard->mask) {
75 SAM("ERROR: 0x%08X=std_id: standard not found\n", \
76 (unsigned int)std_id);
77 return -EINVAL;
79 SAM("selected standard: %s\n", \
80 &(peasycap_standard->v4l2_standard.name[0]));
81 if (peasycap->standard_offset == \
82 (int)(peasycap_standard - &easycap_standard[0])) {
83 SAM("requested standard already in effect\n");
84 return 0;
86 peasycap->standard_offset = (int)(peasycap_standard - &easycap_standard[0]);
87 for (k = 0; k < INPUT_MANY; k++) {
88 if (!peasycap->inputset[k].standard_offset_ok) {
89 peasycap->inputset[k].standard_offset = \
90 peasycap->standard_offset;
93 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
94 peasycap->inputset[peasycap->input].standard_offset = \
95 peasycap->standard_offset;
96 peasycap->inputset[peasycap->input].standard_offset_ok = 1;
97 } else
98 JOM(8, "%i=peasycap->input\n", peasycap->input);
99 peasycap->fps = peasycap_standard->v4l2_standard.frameperiod.denominator / \
100 peasycap_standard->v4l2_standard.frameperiod.numerator;
101 switch (peasycap->fps) {
102 case 6:
103 case 30: {
104 peasycap->ntsc = true;
105 break;
107 case 5:
108 case 25: {
109 peasycap->ntsc = false;
110 break;
112 default: {
113 SAM("MISTAKE: %i=frames-per-second\n", peasycap->fps);
114 return -ENOENT;
117 JOM(8, "%i frames-per-second\n", peasycap->fps);
118 if (0x8000 & peasycap_standard->mask) {
119 peasycap->skip = 5;
120 peasycap->usec = 1000000 / (2 * (5 * peasycap->fps));
121 peasycap->tolerate = 1000 * (25 / (5 * peasycap->fps));
122 } else {
123 peasycap->skip = 0;
124 peasycap->usec = 1000000 / (2 * peasycap->fps);
125 peasycap->tolerate = 1000 * (25 / peasycap->fps);
127 if (peasycap->video_isoc_streaming) {
128 resubmit = true;
129 kill_video_urbs(peasycap);
130 } else
131 resubmit = false;
132 /*--------------------------------------------------------------------------*/
134 * SAA7113H DATASHEET PAGE 44, TABLE 42
136 /*--------------------------------------------------------------------------*/
137 need = 0; itwas = 0; reg = 0x00; set = 0x00;
138 switch (peasycap_standard->mask & 0x000F) {
139 case NTSC_M_JP: {
140 reg = 0x0A; set = 0x95;
141 ir = read_saa(peasycap->pusb_device, reg);
142 if (0 > ir)
143 SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
144 else
145 itwas = (unsigned int)ir;
146 rc = write_saa(peasycap->pusb_device, reg, set);
147 if (0 != rc)
148 SAM("ERROR: failed to set SAA register " \
149 "0x%02X to 0x%02X for JP standard\n", reg, set);
150 else {
151 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
152 if (0 > ir)
153 JOM(8, "SAA register 0x%02X changed " \
154 "to 0x%02X\n", reg, isnow);
155 else
156 JOM(8, "SAA register 0x%02X changed " \
157 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
160 reg = 0x0B; set = 0x48;
161 ir = read_saa(peasycap->pusb_device, reg);
162 if (0 > ir)
163 SAM("ERROR: cannot read SAA register 0x%02X\n", reg);
164 else
165 itwas = (unsigned int)ir;
166 rc = write_saa(peasycap->pusb_device, reg, set);
167 if (0 != rc)
168 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X " \
169 "for JP standard\n", reg, set);
170 else {
171 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
172 if (0 > ir)
173 JOM(8, "SAA register 0x%02X changed " \
174 "to 0x%02X\n", reg, isnow);
175 else
176 JOM(8, "SAA register 0x%02X changed " \
177 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
179 /*--------------------------------------------------------------------------*/
181 * NOTE: NO break HERE: RUN ON TO NEXT CASE
183 /*--------------------------------------------------------------------------*/
185 case NTSC_M:
186 case PAL_BGHIN: {
187 reg = 0x0E; set = 0x01; need = 1; break;
189 case NTSC_N_443:
190 case PAL_60: {
191 reg = 0x0E; set = 0x11; need = 1; break;
193 case NTSC_443:
194 case PAL_Nc: {
195 reg = 0x0E; set = 0x21; need = 1; break;
197 case NTSC_N:
198 case PAL_M: {
199 reg = 0x0E; set = 0x31; need = 1; break;
201 case SECAM: {
202 reg = 0x0E; set = 0x51; need = 1; break;
204 default:
205 break;
207 /*--------------------------------------------------------------------------*/
208 if (need) {
209 ir = read_saa(peasycap->pusb_device, reg);
210 if (0 > ir)
211 SAM("ERROR: failed to read SAA register 0x%02X\n", reg);
212 else
213 itwas = (unsigned int)ir;
214 rc = write_saa(peasycap->pusb_device, reg, set);
215 if (0 != write_saa(peasycap->pusb_device, reg, set)) {
216 SAM("ERROR: failed to set SAA register " \
217 "0x%02X to 0x%02X for table 42\n", reg, set);
218 } else {
219 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
220 if (0 > ir)
221 JOM(8, "SAA register 0x%02X changed " \
222 "to 0x%02X\n", reg, isnow);
223 else
224 JOM(8, "SAA register 0x%02X changed " \
225 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
228 /*--------------------------------------------------------------------------*/
230 * SAA7113H DATASHEET PAGE 41
232 /*--------------------------------------------------------------------------*/
233 reg = 0x08;
234 ir = read_saa(peasycap->pusb_device, reg);
235 if (0 > ir)
236 SAM("ERROR: failed to read SAA register 0x%02X " \
237 "so cannot reset\n", reg);
238 else {
239 itwas = (unsigned int)ir;
240 if (peasycap_standard->mask & 0x0001)
241 set = itwas | 0x40 ;
242 else
243 set = itwas & ~0x40 ;
244 rc = write_saa(peasycap->pusb_device, reg, set);
245 if (0 != rc)
246 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
247 reg, set);
248 else {
249 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
250 if (0 > ir)
251 JOM(8, "SAA register 0x%02X changed to 0x%02X\n", \
252 reg, isnow);
253 else
254 JOM(8, "SAA register 0x%02X changed " \
255 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
258 /*--------------------------------------------------------------------------*/
260 * SAA7113H DATASHEET PAGE 51, TABLE 57
262 /*---------------------------------------------------------------------------*/
263 reg = 0x40;
264 ir = read_saa(peasycap->pusb_device, reg);
265 if (0 > ir)
266 SAM("ERROR: failed to read SAA register 0x%02X " \
267 "so cannot reset\n", reg);
268 else {
269 itwas = (unsigned int)ir;
270 if (peasycap_standard->mask & 0x0001)
271 set = itwas | 0x80 ;
272 else
273 set = itwas & ~0x80 ;
274 rc = write_saa(peasycap->pusb_device, reg, set);
275 if (0 != rc)
276 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
277 reg, set);
278 else {
279 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
280 if (0 > ir)
281 JOM(8, "SAA register 0x%02X changed to 0x%02X\n", \
282 reg, isnow);
283 else
284 JOM(8, "SAA register 0x%02X changed " \
285 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
288 /*--------------------------------------------------------------------------*/
290 * SAA7113H DATASHEET PAGE 53, TABLE 66
292 /*--------------------------------------------------------------------------*/
293 reg = 0x5A;
294 ir = read_saa(peasycap->pusb_device, reg);
295 if (0 > ir)
296 SAM("ERROR: failed to read SAA register 0x%02X but continuing\n", reg);
297 itwas = (unsigned int)ir;
298 if (peasycap_standard->mask & 0x0001)
299 set = 0x0A ;
300 else
301 set = 0x07 ;
302 if (0 != write_saa(peasycap->pusb_device, reg, set))
303 SAM("ERROR: failed to set SAA register 0x%02X to 0x%02X\n", \
304 reg, set);
305 else {
306 isnow = (unsigned int)read_saa(peasycap->pusb_device, reg);
307 if (0 > ir)
308 JOM(8, "SAA register 0x%02X changed "
309 "to 0x%02X\n", reg, isnow);
310 else
311 JOM(8, "SAA register 0x%02X changed "
312 "from 0x%02X to 0x%02X\n", reg, itwas, isnow);
314 if (true == resubmit)
315 submit_video_urbs(peasycap);
316 return 0;
318 /*****************************************************************************/
319 /*--------------------------------------------------------------------------*/
321 * THE ALGORITHM FOR RESPONDING TO THE VIDIO_S_FMT IOCTL REQUIRES
322 * A VALID VALUE OF peasycap->standard_offset, OTHERWISE -EBUSY IS RETURNED.
324 * PROVIDED THE ARGUMENT try IS false AND THERE IS NO PREMATURE ERROR RETURN
325 * THIS ROUTINE UPDATES THE FOLLOWING:
326 * peasycap->format_offset
327 * peasycap->inputset[peasycap->input].format_offset
328 * peasycap->pixelformat
329 * peasycap->height
330 * peasycap->width
331 * peasycap->bytesperpixel
332 * peasycap->byteswaporder
333 * peasycap->decimatepixel
334 * peasycap->frame_buffer_used
335 * peasycap->videofieldamount
336 * peasycap->offerfields
338 * IF SUCCESSFUL THE FUNCTION RETURNS THE OFFSET IN easycap_format[]
339 * IDENTIFYING THE FORMAT WHICH IS TO RETURNED TO THE USER.
340 * ERRORS RETURN A NEGATIVE NUMBER.
342 /*--------------------------------------------------------------------------*/
343 int adjust_format(struct easycap *peasycap, \
344 __u32 width, __u32 height, __u32 pixelformat, int field, bool try)
346 struct easycap_format *peasycap_format, *peasycap_best_format;
347 __u16 mask;
348 struct usb_device *p;
349 int miss, multiplier, best, k;
350 char bf[5], fo[32], *pc;
351 __u32 uc;
352 bool resubmit;
354 if (NULL == peasycap) {
355 SAY("ERROR: peasycap is NULL\n");
356 return -EFAULT;
358 if (0 > peasycap->standard_offset) {
359 JOM(8, "%i=peasycap->standard_offset\n", peasycap->standard_offset);
360 return -EBUSY;
362 p = peasycap->pusb_device;
363 if ((struct usb_device *)NULL == p) {
364 SAM("ERROR: peaycap->pusb_device is NULL\n");
365 return -EFAULT;
367 pc = &bf[0];
368 uc = pixelformat;
369 memcpy((void *)pc, (void *)(&uc), 4);
370 bf[4] = 0;
371 mask = 0xFF & easycap_standard[peasycap->standard_offset].mask;
372 SAM("sought: %ix%i,%s(0x%08X),%i=field,0x%02X=std mask\n", \
373 width, height, pc, pixelformat, field, mask);
374 switch (field) {
375 case V4L2_FIELD_ANY: {
376 strcpy(&fo[0], "V4L2_FIELD_ANY ");
377 break;
379 case V4L2_FIELD_NONE: {
380 strcpy(&fo[0], "V4L2_FIELD_NONE");
381 break;
383 case V4L2_FIELD_TOP: {
384 strcpy(&fo[0], "V4L2_FIELD_TOP");
385 break;
387 case V4L2_FIELD_BOTTOM: {
388 strcpy(&fo[0], "V4L2_FIELD_BOTTOM");
389 break;
391 case V4L2_FIELD_INTERLACED: {
392 strcpy(&fo[0], "V4L2_FIELD_INTERLACED");
393 break;
395 case V4L2_FIELD_SEQ_TB: {
396 strcpy(&fo[0], "V4L2_FIELD_SEQ_TB");
397 break;
399 case V4L2_FIELD_SEQ_BT: {
400 strcpy(&fo[0], "V4L2_FIELD_SEQ_BT");
401 break;
403 case V4L2_FIELD_ALTERNATE: {
404 strcpy(&fo[0], "V4L2_FIELD_ALTERNATE");
405 break;
407 case V4L2_FIELD_INTERLACED_TB: {
408 strcpy(&fo[0], "V4L2_FIELD_INTERLACED_TB");
409 break;
411 case V4L2_FIELD_INTERLACED_BT: {
412 strcpy(&fo[0], "V4L2_FIELD_INTERLACED_BT");
413 break;
415 default: {
416 strcpy(&fo[0], "V4L2_FIELD_... UNKNOWN ");
417 break;
420 SAM("sought: %s\n", &fo[0]);
421 if (V4L2_FIELD_ANY == field) {
422 field = V4L2_FIELD_NONE;
423 SAM("prefer: V4L2_FIELD_NONE=field, was V4L2_FIELD_ANY\n");
425 peasycap_best_format = (struct easycap_format *)NULL;
426 peasycap_format = &easycap_format[0];
427 while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
428 JOM(16, ".> %i %i 0x%08X %ix%i\n", \
429 peasycap_format->mask & 0x01,
430 peasycap_format->v4l2_format.fmt.pix.field,
431 peasycap_format->v4l2_format.fmt.pix.pixelformat,
432 peasycap_format->v4l2_format.fmt.pix.width,
433 peasycap_format->v4l2_format.fmt.pix.height);
435 if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \
436 (peasycap_format->v4l2_format.fmt.pix.field == field) && \
437 (peasycap_format->v4l2_format.fmt.pix.pixelformat == \
438 pixelformat) && \
439 (peasycap_format->v4l2_format.fmt.pix.width == width) && \
440 (peasycap_format->v4l2_format.fmt.pix.height == height)) {
441 peasycap_best_format = peasycap_format;
442 break;
444 peasycap_format++;
446 if (0 == peasycap_format->v4l2_format.fmt.pix.width) {
447 SAM("cannot do: %ix%i with standard mask 0x%02X\n", \
448 width, height, mask);
449 peasycap_format = &easycap_format[0]; best = -1;
450 while (0 != peasycap_format->v4l2_format.fmt.pix.width) {
451 if (((peasycap_format->mask & 0x1F) == (mask & 0x1F)) && \
452 (peasycap_format->v4l2_format.fmt.pix\
453 .field == field) && \
454 (peasycap_format->v4l2_format.fmt.pix\
455 .pixelformat == pixelformat)) {
456 miss = abs(peasycap_format->\
457 v4l2_format.fmt.pix.width - width);
458 if ((best > miss) || (best < 0)) {
459 best = miss;
460 peasycap_best_format = peasycap_format;
461 if (!miss)
462 break;
465 peasycap_format++;
467 if (-1 == best) {
468 SAM("cannot do %ix... with standard mask 0x%02X\n", \
469 width, mask);
470 SAM("cannot do ...x%i with standard mask 0x%02X\n", \
471 height, mask);
472 SAM(" %ix%i unmatched\n", width, height);
473 return peasycap->format_offset;
476 if ((struct easycap_format *)NULL == peasycap_best_format) {
477 SAM("MISTAKE: peasycap_best_format is NULL");
478 return -EINVAL;
480 peasycap_format = peasycap_best_format;
482 /*...........................................................................*/
483 if (true == try)
484 return (int)(peasycap_best_format - &easycap_format[0]);
485 /*...........................................................................*/
487 if (false != try) {
488 SAM("MISTAKE: true==try where is should be false\n");
489 return -EINVAL;
491 SAM("actioning: %ix%i %s\n", \
492 peasycap_format->v4l2_format.fmt.pix.width, \
493 peasycap_format->v4l2_format.fmt.pix.height,
494 &peasycap_format->name[0]);
495 peasycap->height = peasycap_format->v4l2_format.fmt.pix.height;
496 peasycap->width = peasycap_format->v4l2_format.fmt.pix.width;
497 peasycap->pixelformat = peasycap_format->v4l2_format.fmt.pix.pixelformat;
498 peasycap->format_offset = (int)(peasycap_format - &easycap_format[0]);
501 for (k = 0; k < INPUT_MANY; k++) {
502 if (!peasycap->inputset[k].format_offset_ok) {
503 peasycap->inputset[k].format_offset = \
504 peasycap->format_offset;
507 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
508 peasycap->inputset[peasycap->input].format_offset = \
509 peasycap->format_offset;
510 peasycap->inputset[peasycap->input].format_offset_ok = 1;
511 } else
512 JOM(8, "%i=peasycap->input\n", peasycap->input);
516 peasycap->bytesperpixel = (0x00E0 & peasycap_format->mask) >> 5 ;
517 if (0x0100 & peasycap_format->mask)
518 peasycap->byteswaporder = true;
519 else
520 peasycap->byteswaporder = false;
521 if (0x0200 & peasycap_format->mask)
522 peasycap->skip = 5;
523 else
524 peasycap->skip = 0;
525 if (0x0800 & peasycap_format->mask)
526 peasycap->decimatepixel = true;
527 else
528 peasycap->decimatepixel = false;
529 if (0x1000 & peasycap_format->mask)
530 peasycap->offerfields = true;
531 else
532 peasycap->offerfields = false;
533 if (true == peasycap->decimatepixel)
534 multiplier = 2;
535 else
536 multiplier = 1;
537 peasycap->videofieldamount = multiplier * peasycap->width * \
538 multiplier * peasycap->height;
539 peasycap->frame_buffer_used = peasycap->bytesperpixel * \
540 peasycap->width * peasycap->height;
541 if (peasycap->video_isoc_streaming) {
542 resubmit = true;
543 kill_video_urbs(peasycap);
544 } else
545 resubmit = false;
546 /*---------------------------------------------------------------------------*/
548 * PAL
550 /*---------------------------------------------------------------------------*/
551 if (0 == (0x01 & peasycap_format->mask)) {
552 if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
553 (576 == \
554 peasycap_format->v4l2_format.fmt.pix.height)) || \
555 ((360 == \
556 peasycap_format->v4l2_format.fmt.pix.width) && \
557 (288 == \
558 peasycap_format->v4l2_format.fmt.pix.height))) {
559 if (0 != set_resolution(p, 0x0000, 0x0001, 0x05A0, 0x0121)) {
560 SAM("ERROR: set_resolution() failed\n");
561 return -EINVAL;
563 } else if ((704 == peasycap_format->v4l2_format.fmt.pix.width) && \
564 (576 == peasycap_format->v4l2_format.fmt.pix.height)) {
565 if (0 != set_resolution(p, 0x0004, 0x0001, 0x0584, 0x0121)) {
566 SAM("ERROR: set_resolution() failed\n");
567 return -EINVAL;
569 } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
570 (480 == \
571 peasycap_format->v4l2_format.fmt.pix.height)) || \
572 ((320 == \
573 peasycap_format->v4l2_format.fmt.pix.width) && \
574 (240 == \
575 peasycap_format->v4l2_format.fmt.pix.height))) {
576 if (0 != set_resolution(p, 0x0014, 0x0020, 0x0514, 0x0110)) {
577 SAM("ERROR: set_resolution() failed\n");
578 return -EINVAL;
580 } else {
581 SAM("MISTAKE: bad format, cannot set resolution\n");
582 return -EINVAL;
584 /*---------------------------------------------------------------------------*/
586 * NTSC
588 /*---------------------------------------------------------------------------*/
589 } else {
590 if (((720 == peasycap_format->v4l2_format.fmt.pix.width) && \
591 (480 == \
592 peasycap_format->v4l2_format.fmt.pix.height)) || \
593 ((360 == \
594 peasycap_format->v4l2_format.fmt.pix.width) && \
595 (240 == \
596 peasycap_format->v4l2_format.fmt.pix.height))) {
597 if (0 != set_resolution(p, 0x0000, 0x0003, 0x05A0, 0x00F3)) {
598 SAM("ERROR: set_resolution() failed\n");
599 return -EINVAL;
601 } else if (((640 == peasycap_format->v4l2_format.fmt.pix.width) && \
602 (480 == \
603 peasycap_format->v4l2_format.fmt.pix.height)) || \
604 ((320 == \
605 peasycap_format->v4l2_format.fmt.pix.width) && \
606 (240 == \
607 peasycap_format->v4l2_format.fmt.pix.height))) {
608 if (0 != set_resolution(p, 0x0014, 0x0003, 0x0514, 0x00F3)) {
609 SAM("ERROR: set_resolution() failed\n");
610 return -EINVAL;
612 } else {
613 SAM("MISTAKE: bad format, cannot set resolution\n");
614 return -EINVAL;
617 /*---------------------------------------------------------------------------*/
618 if (true == resubmit)
619 submit_video_urbs(peasycap);
620 return (int)(peasycap_best_format - &easycap_format[0]);
622 /*****************************************************************************/
623 int adjust_brightness(struct easycap *peasycap, int value)
625 unsigned int mood;
626 int i1, k;
628 if (NULL == peasycap) {
629 SAY("ERROR: peasycap is NULL\n");
630 return -EFAULT;
632 if ((struct usb_device *)NULL == peasycap->pusb_device) {
633 SAM("ERROR: peasycap->pusb_device is NULL\n");
634 return -EFAULT;
636 i1 = 0;
637 while (0xFFFFFFFF != easycap_control[i1].id) {
638 if (V4L2_CID_BRIGHTNESS == easycap_control[i1].id) {
639 if ((easycap_control[i1].minimum > value) || \
640 (easycap_control[i1].maximum < value))
641 value = easycap_control[i1].default_value;
643 if ((easycap_control[i1].minimum <= peasycap->brightness) && \
644 (easycap_control[i1].maximum >= \
645 peasycap->brightness)) {
646 if (peasycap->brightness == value) {
647 SAM("unchanged brightness at 0x%02X\n", \
648 value);
649 return 0;
652 peasycap->brightness = value;
653 for (k = 0; k < INPUT_MANY; k++) {
654 if (!peasycap->inputset[k].brightness_ok)
655 peasycap->inputset[k].brightness = \
656 peasycap->brightness;
658 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
659 peasycap->inputset[peasycap->input].brightness = \
660 peasycap->brightness;
661 peasycap->inputset[peasycap->input].brightness_ok = 1;
662 } else
663 JOM(8, "%i=peasycap->input\n", peasycap->input);
664 mood = 0x00FF & (unsigned int)peasycap->brightness;
665 if (!write_saa(peasycap->pusb_device, 0x0A, mood)) {
666 SAM("adjusting brightness to 0x%02X\n", mood);
667 return 0;
668 } else {
669 SAM("WARNING: failed to adjust brightness " \
670 "to 0x%02X\n", mood);
671 return -ENOENT;
673 break;
675 i1++;
677 SAM("WARNING: failed to adjust brightness: control not found\n");
678 return -ENOENT;
680 /*****************************************************************************/
681 int adjust_contrast(struct easycap *peasycap, int value)
683 unsigned int mood;
684 int i1, k;
686 if (NULL == peasycap) {
687 SAY("ERROR: peasycap is NULL\n");
688 return -EFAULT;
690 if ((struct usb_device *)NULL == peasycap->pusb_device) {
691 SAM("ERROR: peasycap->pusb_device is NULL\n");
692 return -EFAULT;
694 i1 = 0;
695 while (0xFFFFFFFF != easycap_control[i1].id) {
696 if (V4L2_CID_CONTRAST == easycap_control[i1].id) {
697 if ((easycap_control[i1].minimum > value) || \
698 (easycap_control[i1].maximum < value))
699 value = easycap_control[i1].default_value;
703 if ((easycap_control[i1].minimum <= peasycap->contrast) && \
704 (easycap_control[i1].maximum >= \
705 peasycap->contrast)) {
706 if (peasycap->contrast == value) {
707 SAM("unchanged contrast at 0x%02X\n", value);
708 return 0;
711 peasycap->contrast = value;
712 for (k = 0; k < INPUT_MANY; k++) {
713 if (!peasycap->inputset[k].contrast_ok) {
714 peasycap->inputset[k].contrast = \
715 peasycap->contrast;
718 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
719 peasycap->inputset[peasycap->input].contrast = \
720 peasycap->contrast;
721 peasycap->inputset[peasycap->input].contrast_ok = 1;
722 } else
723 JOM(8, "%i=peasycap->input\n", peasycap->input);
724 mood = 0x00FF & (unsigned int) (peasycap->contrast - 128);
725 if (!write_saa(peasycap->pusb_device, 0x0B, mood)) {
726 SAM("adjusting contrast to 0x%02X\n", mood);
727 return 0;
728 } else {
729 SAM("WARNING: failed to adjust contrast to " \
730 "0x%02X\n", mood);
731 return -ENOENT;
733 break;
735 i1++;
737 SAM("WARNING: failed to adjust contrast: control not found\n");
738 return -ENOENT;
740 /*****************************************************************************/
741 int adjust_saturation(struct easycap *peasycap, int value)
743 unsigned int mood;
744 int i1, k;
746 if (NULL == peasycap) {
747 SAY("ERROR: peasycap is NULL\n");
748 return -EFAULT;
750 if ((struct usb_device *)NULL == peasycap->pusb_device) {
751 SAM("ERROR: peasycap->pusb_device is NULL\n");
752 return -EFAULT;
754 i1 = 0;
755 while (0xFFFFFFFF != easycap_control[i1].id) {
756 if (V4L2_CID_SATURATION == easycap_control[i1].id) {
757 if ((easycap_control[i1].minimum > value) || \
758 (easycap_control[i1].maximum < value))
759 value = easycap_control[i1].default_value;
762 if ((easycap_control[i1].minimum <= peasycap->saturation) && \
763 (easycap_control[i1].maximum >= \
764 peasycap->saturation)) {
765 if (peasycap->saturation == value) {
766 SAM("unchanged saturation at 0x%02X\n", \
767 value);
768 return 0;
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;
778 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
779 peasycap->inputset[peasycap->input].saturation = \
780 peasycap->saturation;
781 peasycap->inputset[peasycap->input].saturation_ok = 1;
782 } else
783 JOM(8, "%i=peasycap->input\n", peasycap->input);
784 mood = 0x00FF & (unsigned int) (peasycap->saturation - 128);
785 if (!write_saa(peasycap->pusb_device, 0x0C, mood)) {
786 SAM("adjusting saturation to 0x%02X\n", mood);
787 return 0;
788 } else {
789 SAM("WARNING: failed to adjust saturation to " \
790 "0x%02X\n", mood);
791 return -ENOENT;
793 break;
795 i1++;
797 SAM("WARNING: failed to adjust saturation: control not found\n");
798 return -ENOENT;
800 /*****************************************************************************/
801 int adjust_hue(struct easycap *peasycap, int value)
803 unsigned int mood;
804 int i1, i2, k;
806 if (NULL == peasycap) {
807 SAY("ERROR: peasycap is NULL\n");
808 return -EFAULT;
810 if ((struct usb_device *)NULL == peasycap->pusb_device) {
811 SAM("ERROR: peasycap->pusb_device is NULL\n");
812 return -EFAULT;
814 i1 = 0;
815 while (0xFFFFFFFF != easycap_control[i1].id) {
816 if (V4L2_CID_HUE == easycap_control[i1].id) {
817 if ((easycap_control[i1].minimum > value) || \
818 (easycap_control[i1].maximum < value))
819 value = easycap_control[i1].default_value;
821 if ((easycap_control[i1].minimum <= peasycap->hue) && \
822 (easycap_control[i1].maximum >= \
823 peasycap->hue)) {
824 if (peasycap->hue == value) {
825 SAM("unchanged hue at 0x%02X\n", value);
826 return 0;
829 peasycap->hue = value;
830 for (k = 0; k < INPUT_MANY; k++) {
831 if (!peasycap->inputset[k].hue_ok)
832 peasycap->inputset[k].hue = peasycap->hue;
834 if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) {
835 peasycap->inputset[peasycap->input].hue = \
836 peasycap->hue;
837 peasycap->inputset[peasycap->input].hue_ok = 1;
838 } else
839 JOM(8, "%i=peasycap->input\n", peasycap->input);
840 i2 = peasycap->hue - 128;
841 mood = 0x00FF & ((int) i2);
842 if (!write_saa(peasycap->pusb_device, 0x0D, mood)) {
843 SAM("adjusting hue to 0x%02X\n", mood);
844 return 0;
845 } else {
846 SAM("WARNING: failed to adjust hue to 0x%02X\n", mood);
847 return -ENOENT;
849 break;
851 i1++;
853 SAM("WARNING: failed to adjust hue: control not found\n");
854 return -ENOENT;
856 /*****************************************************************************/
857 int adjust_volume(struct easycap *peasycap, int value)
859 __s8 mood;
860 int i1;
862 if (NULL == peasycap) {
863 SAY("ERROR: peasycap is NULL\n");
864 return -EFAULT;
866 if ((struct usb_device *)NULL == peasycap->pusb_device) {
867 SAM("ERROR: peasycap->pusb_device is NULL\n");
868 return -EFAULT;
870 i1 = 0;
871 while (0xFFFFFFFF != easycap_control[i1].id) {
872 if (V4L2_CID_AUDIO_VOLUME == easycap_control[i1].id) {
873 if ((easycap_control[i1].minimum > value) || \
874 (easycap_control[i1].maximum < value))
875 value = easycap_control[i1].default_value;
876 if ((easycap_control[i1].minimum <= peasycap->volume) && \
877 (easycap_control[i1].maximum >= \
878 peasycap->volume)) {
879 if (peasycap->volume == value) {
880 SAM("unchanged volume at 0x%02X\n", value);
881 return 0;
884 peasycap->volume = value;
885 mood = (16 > peasycap->volume) ? 16 : \
886 ((31 < peasycap->volume) ? 31 : \
887 (__s8) peasycap->volume);
888 if (!audio_gainset(peasycap->pusb_device, mood)) {
889 SAM("adjusting volume to 0x%02X\n", mood);
890 return 0;
891 } else {
892 SAM("WARNING: failed to adjust volume to " \
893 "0x%2X\n", mood);
894 return -ENOENT;
896 break;
898 i1++;
900 SAM("WARNING: failed to adjust volume: control not found\n");
901 return -ENOENT;
903 /*****************************************************************************/
904 /*---------------------------------------------------------------------------*/
906 * AN ALTERNATIVE METHOD OF MUTING MIGHT SEEM TO BE:
907 * usb_set_interface(peasycap->pusb_device, \
908 * peasycap->audio_interface, \
909 * peasycap->audio_altsetting_off);
910 * HOWEVER, AFTER THIS COMMAND IS ISSUED ALL SUBSEQUENT URBS RECEIVE STATUS
911 * -ESHUTDOWN. THE HANDLER ROUTINE easyxxx_complete() DECLINES TO RESUBMIT
912 * THE URB AND THE PIPELINE COLLAPSES IRRETRIEVABLY. BEWARE.
914 /*---------------------------------------------------------------------------*/
915 int adjust_mute(struct easycap *peasycap, int value)
917 int i1;
919 if (NULL == peasycap) {
920 SAY("ERROR: peasycap is NULL\n");
921 return -EFAULT;
923 if ((struct usb_device *)NULL == peasycap->pusb_device) {
924 SAM("ERROR: peasycap->pusb_device is NULL\n");
925 return -EFAULT;
927 i1 = 0;
928 while (0xFFFFFFFF != easycap_control[i1].id) {
929 if (V4L2_CID_AUDIO_MUTE == easycap_control[i1].id) {
930 peasycap->mute = value;
931 switch (peasycap->mute) {
932 case 1: {
933 peasycap->audio_idle = 1;
934 peasycap->timeval0.tv_sec = 0;
935 SAM("adjusting mute: %i=peasycap->audio_idle\n", \
936 peasycap->audio_idle);
937 return 0;
939 default: {
940 peasycap->audio_idle = 0;
941 SAM("adjusting mute: %i=peasycap->audio_idle\n", \
942 peasycap->audio_idle);
943 return 0;
946 break;
948 i1++;
950 SAM("WARNING: failed to adjust mute: control not found\n");
951 return -ENOENT;
953 /*****************************************************************************/
954 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
955 #if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
956 (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
957 long
958 easycap_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
959 return (long)easycap_ioctl((struct inode *)NULL, file, cmd, arg);
961 #endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
962 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
963 /*---------------------------------------------------------------------------*/
965 easycap_ioctl(struct inode *inode, struct file *file,
966 unsigned int cmd, unsigned long arg)
968 struct easycap *peasycap;
969 struct usb_device *p;
970 int kd;
972 if (NULL == file) {
973 SAY("ERROR: file is NULL\n");
974 return -ERESTARTSYS;
976 peasycap = file->private_data;
977 if (NULL == peasycap) {
978 SAY("ERROR: peasycap is NULL\n");
979 return -1;
981 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
982 SAY("ERROR: bad peasycap\n");
983 return -EFAULT;
985 p = peasycap->pusb_device;
986 if (NULL == p) {
987 SAM("ERROR: peasycap->pusb_device is NULL\n");
988 return -EFAULT;
990 kd = isdongle(peasycap);
991 if (0 <= kd && DONGLE_MANY > kd) {
992 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
993 SAY("ERROR: cannot lock " \
994 "easycapdc60_dongle[%i].mutex_video\n", kd);
995 return -ERESTARTSYS;
997 JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd);
998 /*---------------------------------------------------------------------------*/
1000 * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
1001 * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
1002 * IF NECESSARY, BAIL OUT.
1004 /*---------------------------------------------------------------------------*/
1005 if (kd != isdongle(peasycap))
1006 return -ERESTARTSYS;
1007 if (NULL == file) {
1008 SAY("ERROR: file is NULL\n");
1009 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1010 return -ERESTARTSYS;
1012 peasycap = file->private_data;
1013 if (NULL == peasycap) {
1014 SAY("ERROR: peasycap is NULL\n");
1015 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1016 return -ERESTARTSYS;
1018 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
1019 SAY("ERROR: bad peasycap\n");
1020 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1021 return -EFAULT;
1023 p = peasycap->pusb_device;
1024 if (NULL == peasycap->pusb_device) {
1025 SAM("ERROR: peasycap->pusb_device is NULL\n");
1026 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1027 return -ERESTARTSYS;
1029 } else {
1030 /*---------------------------------------------------------------------------*/
1032 * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
1033 * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
1035 /*---------------------------------------------------------------------------*/
1036 return -ERESTARTSYS;
1038 /*---------------------------------------------------------------------------*/
1039 switch (cmd) {
1040 case VIDIOC_QUERYCAP: {
1041 struct v4l2_capability v4l2_capability;
1042 char version[16], *p1, *p2;
1043 int i, rc, k[3];
1044 long lng;
1046 JOM(8, "VIDIOC_QUERYCAP\n");
1048 if (16 <= strlen(EASYCAP_DRIVER_VERSION)) {
1049 SAM("ERROR: bad driver version string\n");
1050 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1051 return -EINVAL;
1053 strcpy(&version[0], EASYCAP_DRIVER_VERSION);
1054 for (i = 0; i < 3; i++)
1055 k[i] = 0;
1056 p2 = &version[0]; i = 0;
1057 while (*p2) {
1058 p1 = p2;
1059 while (*p2 && ('.' != *p2))
1060 p2++;
1061 if (*p2)
1062 *p2++ = 0;
1063 if (3 > i) {
1064 rc = (int) strict_strtol(p1, 10, &lng);
1065 if (0 != rc) {
1066 SAM("ERROR: %i=strict_strtol(%s,.,,)\n", \
1067 rc, p1);
1068 mutex_unlock(&easycapdc60_dongle[kd].\
1069 mutex_video);
1070 return -EINVAL;
1072 k[i] = (int)lng;
1074 i++;
1077 memset(&v4l2_capability, 0, sizeof(struct v4l2_capability));
1078 strlcpy(&v4l2_capability.driver[0], "easycap", \
1079 sizeof(v4l2_capability.driver));
1081 v4l2_capability.capabilities = \
1082 V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
1083 V4L2_CAP_AUDIO | V4L2_CAP_READWRITE;
1085 v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]);
1086 JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]);
1088 strlcpy(&v4l2_capability.card[0], "EasyCAP DC60", \
1089 sizeof(v4l2_capability.card));
1091 if (usb_make_path(peasycap->pusb_device, &v4l2_capability.bus_info[0],\
1092 sizeof(v4l2_capability.bus_info)) < 0) {
1093 strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", \
1094 sizeof(v4l2_capability.bus_info));
1095 JOM(8, "%s=v4l2_capability.bus_info\n", \
1096 &v4l2_capability.bus_info[0]);
1098 if (0 != copy_to_user((void __user *)arg, &v4l2_capability, \
1099 sizeof(struct v4l2_capability))) {
1100 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1101 return -EFAULT;
1103 break;
1105 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1106 case VIDIOC_ENUMINPUT: {
1107 struct v4l2_input v4l2_input;
1108 __u32 index;
1110 JOM(8, "VIDIOC_ENUMINPUT\n");
1112 if (0 != copy_from_user(&v4l2_input, (void __user *)arg, \
1113 sizeof(struct v4l2_input))) {
1114 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1115 return -EFAULT;
1118 index = v4l2_input.index;
1119 memset(&v4l2_input, 0, sizeof(struct v4l2_input));
1121 switch (index) {
1122 case 0: {
1123 v4l2_input.index = index;
1124 strcpy(&v4l2_input.name[0], "CVBS0");
1125 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1126 v4l2_input.audioset = 0x01;
1127 v4l2_input.tuner = 0;
1128 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
1129 V4L2_STD_NTSC ;
1130 v4l2_input.status = 0;
1131 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1132 break;
1134 case 1: {
1135 v4l2_input.index = index;
1136 strcpy(&v4l2_input.name[0], "CVBS1");
1137 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1138 v4l2_input.audioset = 0x01;
1139 v4l2_input.tuner = 0;
1140 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
1141 V4L2_STD_NTSC ;
1142 v4l2_input.status = 0;
1143 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1144 break;
1146 case 2: {
1147 v4l2_input.index = index;
1148 strcpy(&v4l2_input.name[0], "CVBS2");
1149 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1150 v4l2_input.audioset = 0x01;
1151 v4l2_input.tuner = 0;
1152 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
1153 V4L2_STD_NTSC ;
1154 v4l2_input.status = 0;
1155 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1156 break;
1158 case 3: {
1159 v4l2_input.index = index;
1160 strcpy(&v4l2_input.name[0], "CVBS3");
1161 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1162 v4l2_input.audioset = 0x01;
1163 v4l2_input.tuner = 0;
1164 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
1165 V4L2_STD_NTSC ;
1166 v4l2_input.status = 0;
1167 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1168 break;
1170 case 4: {
1171 v4l2_input.index = index;
1172 strcpy(&v4l2_input.name[0], "CVBS4");
1173 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1174 v4l2_input.audioset = 0x01;
1175 v4l2_input.tuner = 0;
1176 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
1177 V4L2_STD_NTSC ;
1178 v4l2_input.status = 0;
1179 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1180 break;
1182 case 5: {
1183 v4l2_input.index = index;
1184 strcpy(&v4l2_input.name[0], "S-VIDEO");
1185 v4l2_input.type = V4L2_INPUT_TYPE_CAMERA;
1186 v4l2_input.audioset = 0x01;
1187 v4l2_input.tuner = 0;
1188 v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | \
1189 V4L2_STD_NTSC ;
1190 v4l2_input.status = 0;
1191 JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]);
1192 break;
1194 default: {
1195 JOM(8, "%i=index: exhausts inputs\n", index);
1196 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1197 return -EINVAL;
1201 if (0 != copy_to_user((void __user *)arg, &v4l2_input, \
1202 sizeof(struct v4l2_input))) {
1203 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1204 return -EFAULT;
1206 break;
1208 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1209 case VIDIOC_G_INPUT: {
1210 __u32 index;
1212 JOM(8, "VIDIOC_G_INPUT\n");
1213 index = (__u32)peasycap->input;
1214 JOM(8, "user is told: %i\n", index);
1215 if (0 != copy_to_user((void __user *)arg, &index, sizeof(__u32))) {
1216 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1217 return -EFAULT;
1219 break;
1221 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1222 case VIDIOC_S_INPUT:
1224 __u32 index;
1225 int rc;
1227 JOM(8, "VIDIOC_S_INPUT\n");
1229 if (0 != copy_from_user(&index, (void __user *)arg, sizeof(__u32))) {
1230 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1231 return -EFAULT;
1234 JOM(8, "user requests input %i\n", index);
1236 if ((int)index == peasycap->input) {
1237 SAM("requested input already in effect\n");
1238 break;
1241 if ((0 > index) || (INPUT_MANY <= index)) {
1242 JOM(8, "ERROR: bad requested input: %i\n", index);
1243 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1244 return -EINVAL;
1247 rc = newinput(peasycap, (int)index);
1248 if (0 == rc) {
1249 JOM(8, "newinput(.,%i) OK\n", (int)index);
1250 } else {
1251 SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc);
1252 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1253 return -EFAULT;
1255 break;
1257 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1258 case VIDIOC_ENUMAUDIO: {
1259 JOM(8, "VIDIOC_ENUMAUDIO\n");
1260 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1261 return -EINVAL;
1263 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1264 case VIDIOC_ENUMAUDOUT: {
1265 struct v4l2_audioout v4l2_audioout;
1267 JOM(8, "VIDIOC_ENUMAUDOUT\n");
1269 if (0 != copy_from_user(&v4l2_audioout, (void __user *)arg, \
1270 sizeof(struct v4l2_audioout))) {
1271 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1272 return -EFAULT;
1275 if (0 != v4l2_audioout.index) {
1276 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1277 return -EINVAL;
1279 memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout));
1280 v4l2_audioout.index = 0;
1281 strcpy(&v4l2_audioout.name[0], "Soundtrack");
1283 if (0 != copy_to_user((void __user *)arg, &v4l2_audioout, \
1284 sizeof(struct v4l2_audioout))) {
1285 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1286 return -EFAULT;
1288 break;
1290 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1291 case VIDIOC_QUERYCTRL: {
1292 int i1;
1293 struct v4l2_queryctrl v4l2_queryctrl;
1295 JOM(8, "VIDIOC_QUERYCTRL\n");
1297 if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, \
1298 sizeof(struct v4l2_queryctrl))) {
1299 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1300 return -EFAULT;
1303 i1 = 0;
1304 while (0xFFFFFFFF != easycap_control[i1].id) {
1305 if (easycap_control[i1].id == v4l2_queryctrl.id) {
1306 JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" \
1307 ".name\n", &easycap_control[i1].name[0], i1);
1308 memcpy(&v4l2_queryctrl, &easycap_control[i1], \
1309 sizeof(struct v4l2_queryctrl));
1310 break;
1312 i1++;
1314 if (0xFFFFFFFF == easycap_control[i1].id) {
1315 JOM(8, "%i=index: exhausts controls\n", i1);
1316 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1317 return -EINVAL;
1319 if (0 != copy_to_user((void __user *)arg, &v4l2_queryctrl, \
1320 sizeof(struct v4l2_queryctrl))) {
1321 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1322 return -EFAULT;
1324 break;
1326 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1327 case VIDIOC_QUERYMENU: {
1328 JOM(8, "VIDIOC_QUERYMENU unsupported\n");
1329 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1330 return -EINVAL;
1332 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1333 case VIDIOC_G_CTRL: {
1334 struct v4l2_control *pv4l2_control;
1336 JOM(8, "VIDIOC_G_CTRL\n");
1337 pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL);
1338 if (!pv4l2_control) {
1339 SAM("ERROR: out of memory\n");
1340 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1341 return -ENOMEM;
1343 if (0 != copy_from_user(pv4l2_control, (void __user *)arg, \
1344 sizeof(struct v4l2_control))) {
1345 kfree(pv4l2_control);
1346 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1347 return -EFAULT;
1350 switch (pv4l2_control->id) {
1351 case V4L2_CID_BRIGHTNESS: {
1352 pv4l2_control->value = peasycap->brightness;
1353 JOM(8, "user enquires brightness: %i\n", pv4l2_control->value);
1354 break;
1356 case V4L2_CID_CONTRAST: {
1357 pv4l2_control->value = peasycap->contrast;
1358 JOM(8, "user enquires contrast: %i\n", pv4l2_control->value);
1359 break;
1361 case V4L2_CID_SATURATION: {
1362 pv4l2_control->value = peasycap->saturation;
1363 JOM(8, "user enquires saturation: %i\n", pv4l2_control->value);
1364 break;
1366 case V4L2_CID_HUE: {
1367 pv4l2_control->value = peasycap->hue;
1368 JOM(8, "user enquires hue: %i\n", pv4l2_control->value);
1369 break;
1371 case V4L2_CID_AUDIO_VOLUME: {
1372 pv4l2_control->value = peasycap->volume;
1373 JOM(8, "user enquires volume: %i\n", pv4l2_control->value);
1374 break;
1376 case V4L2_CID_AUDIO_MUTE: {
1377 if (1 == peasycap->mute)
1378 pv4l2_control->value = true;
1379 else
1380 pv4l2_control->value = false;
1381 JOM(8, "user enquires mute: %i\n", pv4l2_control->value);
1382 break;
1384 default: {
1385 SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
1386 pv4l2_control->id);
1387 kfree(pv4l2_control);
1388 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1389 return -EINVAL;
1392 if (0 != copy_to_user((void __user *)arg, pv4l2_control, \
1393 sizeof(struct v4l2_control))) {
1394 kfree(pv4l2_control);
1395 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1396 return -EFAULT;
1398 kfree(pv4l2_control);
1399 break;
1401 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1402 #if defined(VIDIOC_S_CTRL_OLD)
1403 case VIDIOC_S_CTRL_OLD: {
1404 JOM(8, "VIDIOC_S_CTRL_OLD required at least for xawtv\n");
1406 #endif /*VIDIOC_S_CTRL_OLD*/
1407 case VIDIOC_S_CTRL:
1409 struct v4l2_control v4l2_control;
1411 JOM(8, "VIDIOC_S_CTRL\n");
1413 if (0 != copy_from_user(&v4l2_control, (void __user *)arg, \
1414 sizeof(struct v4l2_control))) {
1415 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1416 return -EFAULT;
1419 switch (v4l2_control.id) {
1420 case V4L2_CID_BRIGHTNESS: {
1421 JOM(8, "user requests brightness %i\n", v4l2_control.value);
1422 if (0 != adjust_brightness(peasycap, v4l2_control.value))
1424 break;
1426 case V4L2_CID_CONTRAST: {
1427 JOM(8, "user requests contrast %i\n", v4l2_control.value);
1428 if (0 != adjust_contrast(peasycap, v4l2_control.value))
1430 break;
1432 case V4L2_CID_SATURATION: {
1433 JOM(8, "user requests saturation %i\n", v4l2_control.value);
1434 if (0 != adjust_saturation(peasycap, v4l2_control.value))
1436 break;
1438 case V4L2_CID_HUE: {
1439 JOM(8, "user requests hue %i\n", v4l2_control.value);
1440 if (0 != adjust_hue(peasycap, v4l2_control.value))
1442 break;
1444 case V4L2_CID_AUDIO_VOLUME: {
1445 JOM(8, "user requests volume %i\n", v4l2_control.value);
1446 if (0 != adjust_volume(peasycap, v4l2_control.value))
1448 break;
1450 case V4L2_CID_AUDIO_MUTE: {
1451 int mute;
1453 JOM(8, "user requests mute %i\n", v4l2_control.value);
1454 if (true == v4l2_control.value)
1455 mute = 1;
1456 else
1457 mute = 0;
1459 if (0 != adjust_mute(peasycap, mute))
1460 SAM("WARNING: failed to adjust mute to %i\n", mute);
1461 break;
1463 default: {
1464 SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", \
1465 v4l2_control.id);
1466 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1467 return -EINVAL;
1470 break;
1472 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1473 case VIDIOC_S_EXT_CTRLS: {
1474 JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n");
1475 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1476 return -EINVAL;
1478 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1479 case VIDIOC_ENUM_FMT: {
1480 __u32 index;
1481 struct v4l2_fmtdesc v4l2_fmtdesc;
1483 JOM(8, "VIDIOC_ENUM_FMT\n");
1485 if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, \
1486 sizeof(struct v4l2_fmtdesc))) {
1487 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1488 return -EFAULT;
1491 index = v4l2_fmtdesc.index;
1492 memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc));
1494 v4l2_fmtdesc.index = index;
1495 v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1497 switch (index) {
1498 case 0: {
1499 v4l2_fmtdesc.flags = 0;
1500 strcpy(&v4l2_fmtdesc.description[0], "uyvy");
1501 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY;
1502 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1503 break;
1505 case 1: {
1506 v4l2_fmtdesc.flags = 0;
1507 strcpy(&v4l2_fmtdesc.description[0], "yuy2");
1508 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV;
1509 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1510 break;
1512 case 2: {
1513 v4l2_fmtdesc.flags = 0;
1514 strcpy(&v4l2_fmtdesc.description[0], "rgb24");
1515 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24;
1516 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1517 break;
1519 case 3: {
1520 v4l2_fmtdesc.flags = 0;
1521 strcpy(&v4l2_fmtdesc.description[0], "rgb32");
1522 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32;
1523 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1524 break;
1526 case 4: {
1527 v4l2_fmtdesc.flags = 0;
1528 strcpy(&v4l2_fmtdesc.description[0], "bgr24");
1529 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24;
1530 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1531 break;
1533 case 5: {
1534 v4l2_fmtdesc.flags = 0;
1535 strcpy(&v4l2_fmtdesc.description[0], "bgr32");
1536 v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32;
1537 JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]);
1538 break;
1540 default: {
1541 JOM(8, "%i=index: exhausts formats\n", index);
1542 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1543 return -EINVAL;
1546 if (0 != copy_to_user((void __user *)arg, &v4l2_fmtdesc, \
1547 sizeof(struct v4l2_fmtdesc))) {
1548 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1549 return -EFAULT;
1551 break;
1553 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1555 * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE
1556 * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
1558 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1559 case VIDIOC_ENUM_FRAMESIZES: {
1560 __u32 index;
1561 struct v4l2_frmsizeenum v4l2_frmsizeenum;
1563 JOM(8, "VIDIOC_ENUM_FRAMESIZES\n");
1565 if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, \
1566 sizeof(struct v4l2_frmsizeenum))) {
1567 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1568 return -EFAULT;
1571 index = v4l2_frmsizeenum.index;
1573 v4l2_frmsizeenum.type = (__u32) V4L2_FRMSIZE_TYPE_DISCRETE;
1575 if (true == peasycap->ntsc) {
1576 switch (index) {
1577 case 0: {
1578 v4l2_frmsizeenum.discrete.width = 640;
1579 v4l2_frmsizeenum.discrete.height = 480;
1580 JOM(8, "%i=index: %ix%i\n", index, \
1581 (int)(v4l2_frmsizeenum.\
1582 discrete.width), \
1583 (int)(v4l2_frmsizeenum.\
1584 discrete.height));
1585 break;
1587 case 1: {
1588 v4l2_frmsizeenum.discrete.width = 320;
1589 v4l2_frmsizeenum.discrete.height = 240;
1590 JOM(8, "%i=index: %ix%i\n", index, \
1591 (int)(v4l2_frmsizeenum.\
1592 discrete.width), \
1593 (int)(v4l2_frmsizeenum.\
1594 discrete.height));
1595 break;
1597 case 2: {
1598 v4l2_frmsizeenum.discrete.width = 720;
1599 v4l2_frmsizeenum.discrete.height = 480;
1600 JOM(8, "%i=index: %ix%i\n", index, \
1601 (int)(v4l2_frmsizeenum.\
1602 discrete.width), \
1603 (int)(v4l2_frmsizeenum.\
1604 discrete.height));
1605 break;
1607 case 3: {
1608 v4l2_frmsizeenum.discrete.width = 360;
1609 v4l2_frmsizeenum.discrete.height = 240;
1610 JOM(8, "%i=index: %ix%i\n", index, \
1611 (int)(v4l2_frmsizeenum.\
1612 discrete.width), \
1613 (int)(v4l2_frmsizeenum.\
1614 discrete.height));
1615 break;
1617 default: {
1618 JOM(8, "%i=index: exhausts framesizes\n", index);
1619 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1620 return -EINVAL;
1623 } else {
1624 switch (index) {
1625 case 0: {
1626 v4l2_frmsizeenum.discrete.width = 640;
1627 v4l2_frmsizeenum.discrete.height = 480;
1628 JOM(8, "%i=index: %ix%i\n", index, \
1629 (int)(v4l2_frmsizeenum.\
1630 discrete.width), \
1631 (int)(v4l2_frmsizeenum.\
1632 discrete.height));
1633 break;
1635 case 1: {
1636 v4l2_frmsizeenum.discrete.width = 320;
1637 v4l2_frmsizeenum.discrete.height = 240;
1638 JOM(8, "%i=index: %ix%i\n", index, \
1639 (int)(v4l2_frmsizeenum.\
1640 discrete.width), \
1641 (int)(v4l2_frmsizeenum.\
1642 discrete.height));
1643 break;
1645 case 2: {
1646 v4l2_frmsizeenum.discrete.width = 704;
1647 v4l2_frmsizeenum.discrete.height = 576;
1648 JOM(8, "%i=index: %ix%i\n", index, \
1649 (int)(v4l2_frmsizeenum.\
1650 discrete.width), \
1651 (int)(v4l2_frmsizeenum.\
1652 discrete.height));
1653 break;
1655 case 3: {
1656 v4l2_frmsizeenum.discrete.width = 720;
1657 v4l2_frmsizeenum.discrete.height = 576;
1658 JOM(8, "%i=index: %ix%i\n", index, \
1659 (int)(v4l2_frmsizeenum.\
1660 discrete.width), \
1661 (int)(v4l2_frmsizeenum.\
1662 discrete.height));
1663 break;
1665 case 4: {
1666 v4l2_frmsizeenum.discrete.width = 360;
1667 v4l2_frmsizeenum.discrete.height = 288;
1668 JOM(8, "%i=index: %ix%i\n", index, \
1669 (int)(v4l2_frmsizeenum.\
1670 discrete.width), \
1671 (int)(v4l2_frmsizeenum.\
1672 discrete.height));
1673 break;
1675 default: {
1676 JOM(8, "%i=index: exhausts framesizes\n", index);
1677 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1678 return -EINVAL;
1682 if (0 != copy_to_user((void __user *)arg, &v4l2_frmsizeenum, \
1683 sizeof(struct v4l2_frmsizeenum))) {
1684 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1685 return -EFAULT;
1687 break;
1689 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1691 * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE
1692 * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE.
1694 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1695 case VIDIOC_ENUM_FRAMEINTERVALS: {
1696 __u32 index;
1697 int denominator;
1698 struct v4l2_frmivalenum v4l2_frmivalenum;
1700 JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n");
1702 if (peasycap->fps)
1703 denominator = peasycap->fps;
1704 else {
1705 if (true == peasycap->ntsc)
1706 denominator = 30;
1707 else
1708 denominator = 25;
1711 if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, \
1712 sizeof(struct v4l2_frmivalenum))) {
1713 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1714 return -EFAULT;
1717 index = v4l2_frmivalenum.index;
1719 v4l2_frmivalenum.type = (__u32) V4L2_FRMIVAL_TYPE_DISCRETE;
1721 switch (index) {
1722 case 0: {
1723 v4l2_frmivalenum.discrete.numerator = 1;
1724 v4l2_frmivalenum.discrete.denominator = denominator;
1725 JOM(8, "%i=index: %i/%i\n", index, \
1726 (int)(v4l2_frmivalenum.discrete.numerator), \
1727 (int)(v4l2_frmivalenum.discrete.denominator));
1728 break;
1730 case 1: {
1731 v4l2_frmivalenum.discrete.numerator = 1;
1732 v4l2_frmivalenum.discrete.denominator = denominator/5;
1733 JOM(8, "%i=index: %i/%i\n", index, \
1734 (int)(v4l2_frmivalenum.discrete.numerator), \
1735 (int)(v4l2_frmivalenum.discrete.denominator));
1736 break;
1738 default: {
1739 JOM(8, "%i=index: exhausts frameintervals\n", index);
1740 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1741 return -EINVAL;
1744 if (0 != copy_to_user((void __user *)arg, &v4l2_frmivalenum, \
1745 sizeof(struct v4l2_frmivalenum))) {
1746 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1747 return -EFAULT;
1749 break;
1751 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1752 case VIDIOC_G_FMT: {
1753 struct v4l2_format *pv4l2_format;
1754 struct v4l2_pix_format *pv4l2_pix_format;
1756 JOM(8, "VIDIOC_G_FMT\n");
1757 pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL);
1758 if (!pv4l2_format) {
1759 SAM("ERROR: out of memory\n");
1760 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1761 return -ENOMEM;
1763 pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL);
1764 if (!pv4l2_pix_format) {
1765 SAM("ERROR: out of memory\n");
1766 kfree(pv4l2_format);
1767 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1768 return -ENOMEM;
1770 if (0 != copy_from_user(pv4l2_format, (void __user *)arg, \
1771 sizeof(struct v4l2_format))) {
1772 kfree(pv4l2_format);
1773 kfree(pv4l2_pix_format);
1774 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1775 return -EFAULT;
1778 if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1779 kfree(pv4l2_format);
1780 kfree(pv4l2_pix_format);
1781 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1782 return -EINVAL;
1785 memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
1786 pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1787 memcpy(&pv4l2_format->fmt.pix, \
1788 &easycap_format[peasycap->format_offset]\
1789 .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format));
1790 JOM(8, "user is told: %s\n", \
1791 &easycap_format[peasycap->format_offset].name[0]);
1793 if (0 != copy_to_user((void __user *)arg, pv4l2_format, \
1794 sizeof(struct v4l2_format))) {
1795 kfree(pv4l2_format);
1796 kfree(pv4l2_pix_format);
1797 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1798 return -EFAULT;
1800 kfree(pv4l2_format);
1801 kfree(pv4l2_pix_format);
1802 break;
1804 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1805 case VIDIOC_TRY_FMT:
1806 case VIDIOC_S_FMT: {
1807 struct v4l2_format v4l2_format;
1808 struct v4l2_pix_format v4l2_pix_format;
1809 bool try;
1810 int best_format;
1812 if (VIDIOC_TRY_FMT == cmd) {
1813 JOM(8, "VIDIOC_TRY_FMT\n");
1814 try = true;
1815 } else {
1816 JOM(8, "VIDIOC_S_FMT\n");
1817 try = false;
1820 if (0 != copy_from_user(&v4l2_format, (void __user *)arg, \
1821 sizeof(struct v4l2_format))) {
1822 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1823 return -EFAULT;
1826 best_format = adjust_format(peasycap, \
1827 v4l2_format.fmt.pix.width, \
1828 v4l2_format.fmt.pix.height, \
1829 v4l2_format.fmt.pix.pixelformat, \
1830 v4l2_format.fmt.pix.field, \
1831 try);
1832 if (0 > best_format) {
1833 if (-EBUSY == best_format) {
1834 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1835 return -EBUSY;
1837 JOM(8, "WARNING: adjust_format() returned %i\n", best_format);
1838 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1839 return -ENOENT;
1841 /*...........................................................................*/
1842 memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format));
1843 v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1845 memcpy(&(v4l2_format.fmt.pix), &(easycap_format[best_format]\
1846 .v4l2_format.fmt.pix), sizeof(v4l2_pix_format));
1847 JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]);
1849 if (0 != copy_to_user((void __user *)arg, &v4l2_format, \
1850 sizeof(struct v4l2_format))) {
1851 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1852 return -EFAULT;
1854 break;
1856 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1857 case VIDIOC_CROPCAP: {
1858 struct v4l2_cropcap v4l2_cropcap;
1860 JOM(8, "VIDIOC_CROPCAP\n");
1862 if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, \
1863 sizeof(struct v4l2_cropcap))) {
1864 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1865 return -EFAULT;
1868 if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1869 JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
1871 memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap));
1872 v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1873 v4l2_cropcap.bounds.left = 0;
1874 v4l2_cropcap.bounds.top = 0;
1875 v4l2_cropcap.bounds.width = peasycap->width;
1876 v4l2_cropcap.bounds.height = peasycap->height;
1877 v4l2_cropcap.defrect.left = 0;
1878 v4l2_cropcap.defrect.top = 0;
1879 v4l2_cropcap.defrect.width = peasycap->width;
1880 v4l2_cropcap.defrect.height = peasycap->height;
1881 v4l2_cropcap.pixelaspect.numerator = 1;
1882 v4l2_cropcap.pixelaspect.denominator = 1;
1884 JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height);
1886 if (0 != copy_to_user((void __user *)arg, &v4l2_cropcap, \
1887 sizeof(struct v4l2_cropcap))) {
1888 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1889 return -EFAULT;
1891 break;
1893 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1894 case VIDIOC_G_CROP:
1895 case VIDIOC_S_CROP: {
1896 JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n");
1897 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1898 return -EINVAL;
1900 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1901 case VIDIOC_QUERYSTD: {
1902 JOM(8, "VIDIOC_QUERYSTD: " \
1903 "EasyCAP is incapable of detecting standard\n");
1904 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1905 return -EINVAL;
1906 break;
1908 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1909 /*---------------------------------------------------------------------------*/
1911 * THE MANIPULATIONS INVOLVING last0,last1,last2,last3 CONSTITUTE A WORKAROUND
1912 * FOR WHAT APPEARS TO BE A BUG IN 64-BIT mplayer.
1913 * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer.
1915 /*---------------------------------------------------------------------------*/
1916 case VIDIOC_ENUMSTD: {
1917 int last0 = -1, last1 = -1, last2 = -1, last3 = -1;
1918 struct v4l2_standard v4l2_standard;
1919 __u32 index;
1920 struct easycap_standard const *peasycap_standard;
1922 JOM(8, "VIDIOC_ENUMSTD\n");
1924 if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, \
1925 sizeof(struct v4l2_standard))) {
1926 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1927 return -EFAULT;
1929 index = v4l2_standard.index;
1931 last3 = last2; last2 = last1; last1 = last0; last0 = index;
1932 if ((index == last3) && (index == last2) && \
1933 (index == last1) && (index == last0)) {
1934 index++;
1935 last3 = last2; last2 = last1; last1 = last0; last0 = index;
1938 memset(&v4l2_standard, 0, sizeof(struct v4l2_standard));
1940 peasycap_standard = &easycap_standard[0];
1941 while (0xFFFF != peasycap_standard->mask) {
1942 if ((int)(peasycap_standard - &easycap_standard[0]) == index)
1943 break;
1944 peasycap_standard++;
1946 if (0xFFFF == peasycap_standard->mask) {
1947 JOM(8, "%i=index: exhausts standards\n", index);
1948 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1949 return -EINVAL;
1951 JOM(8, "%i=index: %s\n", index, \
1952 &(peasycap_standard->v4l2_standard.name[0]));
1953 memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), \
1954 sizeof(struct v4l2_standard));
1956 v4l2_standard.index = index;
1958 if (0 != copy_to_user((void __user *)arg, &v4l2_standard, \
1959 sizeof(struct v4l2_standard))) {
1960 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1961 return -EFAULT;
1963 break;
1965 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1966 case VIDIOC_G_STD: {
1967 v4l2_std_id std_id;
1968 struct easycap_standard const *peasycap_standard;
1970 JOM(8, "VIDIOC_G_STD\n");
1972 if (0 > peasycap->standard_offset) {
1973 JOM(8, "%i=peasycap->standard_offset\n", \
1974 peasycap->standard_offset);
1975 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1976 return -EBUSY;
1979 if (0 != copy_from_user(&std_id, (void __user *)arg, \
1980 sizeof(v4l2_std_id))) {
1981 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1982 return -EFAULT;
1985 peasycap_standard = &easycap_standard[peasycap->standard_offset];
1986 std_id = peasycap_standard->v4l2_standard.id;
1988 JOM(8, "user is told: %s\n", \
1989 &peasycap_standard->v4l2_standard.name[0]);
1991 if (0 != copy_to_user((void __user *)arg, &std_id, \
1992 sizeof(v4l2_std_id))) {
1993 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
1994 return -EFAULT;
1996 break;
1998 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1999 case VIDIOC_S_STD: {
2000 v4l2_std_id std_id;
2001 int rc;
2003 JOM(8, "VIDIOC_S_STD\n");
2005 if (0 != copy_from_user(&std_id, (void __user *)arg, \
2006 sizeof(v4l2_std_id))) {
2007 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2008 return -EFAULT;
2011 JOM(8, "User requests standard: 0x%08X%08X\n", \
2012 (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), \
2013 (int)(std_id & ((v4l2_std_id)0xFFFFFFFF)));
2015 rc = adjust_standard(peasycap, std_id);
2016 if (0 > rc) {
2017 JOM(8, "WARNING: adjust_standard() returned %i\n", rc);
2018 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2019 return -ENOENT;
2021 break;
2023 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2024 case VIDIOC_REQBUFS: {
2025 int nbuffers;
2026 struct v4l2_requestbuffers v4l2_requestbuffers;
2028 JOM(8, "VIDIOC_REQBUFS\n");
2030 if (0 != copy_from_user(&v4l2_requestbuffers, (void __user *)arg, \
2031 sizeof(struct v4l2_requestbuffers))) {
2032 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2033 return -EFAULT;
2036 if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2037 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2038 return -EINVAL;
2040 if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) {
2041 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2042 return -EINVAL;
2044 nbuffers = v4l2_requestbuffers.count;
2045 JOM(8, " User requests %i buffers ...\n", nbuffers);
2046 if (nbuffers < 2)
2047 nbuffers = 2;
2048 if (nbuffers > FRAME_BUFFER_MANY)
2049 nbuffers = FRAME_BUFFER_MANY;
2050 if (v4l2_requestbuffers.count == nbuffers) {
2051 JOM(8, " ... agree to %i buffers\n", \
2052 nbuffers);
2053 } else {
2054 JOM(8, " ... insist on %i buffers\n", \
2055 nbuffers);
2056 v4l2_requestbuffers.count = nbuffers;
2058 peasycap->frame_buffer_many = nbuffers;
2060 if (0 != copy_to_user((void __user *)arg, &v4l2_requestbuffers, \
2061 sizeof(struct v4l2_requestbuffers))) {
2062 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2063 return -EFAULT;
2065 break;
2067 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2068 case VIDIOC_QUERYBUF: {
2069 __u32 index;
2070 struct v4l2_buffer v4l2_buffer;
2072 JOM(8, "VIDIOC_QUERYBUF\n");
2074 if (peasycap->video_eof) {
2075 JOM(8, "returning -EIO because %i=video_eof\n", \
2076 peasycap->video_eof);
2077 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2078 return -EIO;
2081 if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
2082 sizeof(struct v4l2_buffer))) {
2083 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2084 return -EFAULT;
2087 if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2088 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2089 return -EINVAL;
2091 index = v4l2_buffer.index;
2092 if (index < 0 || index >= peasycap->frame_buffer_many)
2093 return -EINVAL;
2094 memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer));
2095 v4l2_buffer.index = index;
2096 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2097 v4l2_buffer.bytesused = peasycap->frame_buffer_used;
2098 v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | \
2099 peasycap->done[index] | \
2100 peasycap->queued[index];
2101 v4l2_buffer.field = V4L2_FIELD_NONE;
2102 v4l2_buffer.memory = V4L2_MEMORY_MMAP;
2103 v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE;
2104 v4l2_buffer.length = FRAME_BUFFER_SIZE;
2106 JOM(16, " %10i=index\n", v4l2_buffer.index);
2107 JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
2108 JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
2109 JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
2110 JOM(16, " %10i=field\n", v4l2_buffer.field);
2111 JOM(16, " %10li=timestamp.tv_usec\n", \
2112 (long)v4l2_buffer.timestamp.tv_usec);
2113 JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
2114 JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
2115 JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
2116 JOM(16, " %10i=length\n", v4l2_buffer.length);
2118 if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
2119 sizeof(struct v4l2_buffer))) {
2120 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2121 return -EFAULT;
2123 break;
2125 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2126 case VIDIOC_QBUF: {
2127 struct v4l2_buffer v4l2_buffer;
2129 JOM(8, "VIDIOC_QBUF\n");
2131 if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
2132 sizeof(struct v4l2_buffer))) {
2133 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2134 return -EFAULT;
2137 if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2138 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2139 return -EINVAL;
2141 if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) {
2142 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2143 return -EINVAL;
2145 if (v4l2_buffer.index < 0 || \
2146 (v4l2_buffer.index >= peasycap->frame_buffer_many)) {
2147 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2148 return -EINVAL;
2150 v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED;
2152 peasycap->done[v4l2_buffer.index] = 0;
2153 peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED;
2155 if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
2156 sizeof(struct v4l2_buffer))) {
2157 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2158 return -EFAULT;
2161 JOM(8, "..... user queueing frame buffer %i\n", \
2162 (int)v4l2_buffer.index);
2164 peasycap->frame_lock = 0;
2166 break;
2168 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2169 case VIDIOC_DQBUF:
2171 #if defined(AUDIOTIME)
2172 struct signed_div_result sdr;
2173 long long int above, below, dnbydt, fudge, sll;
2174 unsigned long long int ull;
2175 struct timeval timeval8;
2176 struct timeval timeval1;
2177 #endif /*AUDIOTIME*/
2178 struct timeval timeval, timeval2;
2179 int i, j;
2180 struct v4l2_buffer v4l2_buffer;
2181 int rcdq;
2182 __u16 input;
2184 JOM(8, "VIDIOC_DQBUF\n");
2186 if ((peasycap->video_idle) || (peasycap->video_eof)) {
2187 JOM(8, "returning -EIO because " \
2188 "%i=video_idle %i=video_eof\n", \
2189 peasycap->video_idle, peasycap->video_eof);
2190 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2191 return -EIO;
2194 if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, \
2195 sizeof(struct v4l2_buffer))) {
2196 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2197 return -EFAULT;
2200 if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2201 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2202 return -EINVAL;
2205 if (true == peasycap->offerfields) {
2206 /*-----------------------------------------------------------*/
2208 * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST
2209 * V4L2_FIELD_BOTTOM
2211 /*-----------------------------------------------------------*/
2212 if (V4L2_FIELD_TOP == v4l2_buffer.field)
2213 JOM(8, "user wants V4L2_FIELD_TOP\n");
2214 else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field)
2215 JOM(8, "user wants V4L2_FIELD_BOTTOM\n");
2216 else if (V4L2_FIELD_ANY == v4l2_buffer.field)
2217 JOM(8, "user wants V4L2_FIELD_ANY\n");
2218 else
2219 JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", \
2220 v4l2_buffer.field);
2223 if (!peasycap->video_isoc_streaming) {
2224 JOM(16, "returning -EIO because video urbs not streaming\n");
2225 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2226 return -EIO;
2228 /*---------------------------------------------------------------------------*/
2230 * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), AS DETERMINED BY FINDING
2231 * THE FLAG peasycap->polled SET, THERE MUST BE NO FURTHER WAIT HERE. IN THIS
2232 * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read
2234 /*---------------------------------------------------------------------------*/
2236 if (!peasycap->polled) {
2237 do {
2238 rcdq = easycap_dqbuf(peasycap, 0);
2239 if (-EIO == rcdq) {
2240 JOM(8, "returning -EIO because " \
2241 "dqbuf() returned -EIO\n");
2242 mutex_unlock(&easycapdc60_dongle[kd].\
2243 mutex_video);
2244 return -EIO;
2246 } while (0 != rcdq);
2247 } else {
2248 if (peasycap->video_eof) {
2249 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2250 return -EIO;
2253 if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) {
2254 JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n", \
2255 peasycap->done[peasycap->frame_read]);
2257 peasycap->polled = 0;
2259 if (!(peasycap->isequence % 10)) {
2260 for (i = 0; i < 179; i++)
2261 peasycap->merit[i] = peasycap->merit[i+1];
2262 peasycap->merit[179] = merit_saa(peasycap->pusb_device);
2263 j = 0;
2264 for (i = 0; i < 180; i++)
2265 j += peasycap->merit[i];
2266 if (90 < j) {
2267 SAM("easycap driver shutting down " \
2268 "on condition blue\n");
2269 peasycap->video_eof = 1; peasycap->audio_eof = 1;
2273 v4l2_buffer.index = peasycap->frame_read;
2274 v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2275 v4l2_buffer.bytesused = peasycap->frame_buffer_used;
2276 v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE;
2277 if (true == peasycap->offerfields)
2278 v4l2_buffer.field = V4L2_FIELD_BOTTOM;
2279 else
2280 v4l2_buffer.field = V4L2_FIELD_NONE;
2281 do_gettimeofday(&timeval);
2282 timeval2 = timeval;
2284 #if defined(AUDIOTIME)
2285 if (!peasycap->timeval0.tv_sec) {
2286 timeval8 = timeval;
2287 timeval1 = timeval;
2288 timeval2 = timeval;
2289 dnbydt = 192000;
2290 peasycap->timeval0 = timeval8;
2291 } else {
2292 dnbydt = peasycap->dnbydt;
2293 timeval1 = peasycap->timeval1;
2294 above = dnbydt * MICROSECONDS(timeval, timeval1);
2295 below = 192000;
2296 sdr = signed_div(above, below);
2298 above = sdr.quotient + timeval1.tv_usec - 350000;
2300 below = 1000000;
2301 sdr = signed_div(above, below);
2302 timeval2.tv_usec = sdr.remainder;
2303 timeval2.tv_sec = timeval1.tv_sec + sdr.quotient;
2305 if (!(peasycap->isequence % 500)) {
2306 fudge = ((long long int)(1000000)) * \
2307 ((long long int)(timeval.tv_sec - \
2308 timeval2.tv_sec)) + \
2309 (long long int)(timeval.tv_usec - \
2310 timeval2.tv_usec);
2311 sdr = signed_div(fudge, 1000);
2312 sll = sdr.quotient;
2313 ull = sdr.remainder;
2315 SAM("%5lli.%-3lli=ms timestamp fudge\n", sll, ull);
2317 #endif /*AUDIOTIME*/
2319 v4l2_buffer.timestamp = timeval2;
2320 v4l2_buffer.sequence = peasycap->isequence++;
2321 v4l2_buffer.memory = V4L2_MEMORY_MMAP;
2322 v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE;
2323 v4l2_buffer.length = FRAME_BUFFER_SIZE;
2325 JOM(16, " %10i=index\n", v4l2_buffer.index);
2326 JOM(16, " 0x%08X=type\n", v4l2_buffer.type);
2327 JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused);
2328 JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags);
2329 JOM(16, " %10i=field\n", v4l2_buffer.field);
2330 JOM(16, " %10li=timestamp.tv_sec\n", \
2331 (long)v4l2_buffer.timestamp.tv_sec);
2332 JOM(16, " %10li=timestamp.tv_usec\n", \
2333 (long)v4l2_buffer.timestamp.tv_usec);
2334 JOM(16, " %10i=sequence\n", v4l2_buffer.sequence);
2335 JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory);
2336 JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset);
2337 JOM(16, " %10i=length\n", v4l2_buffer.length);
2339 if (0 != copy_to_user((void __user *)arg, &v4l2_buffer, \
2340 sizeof(struct v4l2_buffer))) {
2341 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2342 return -EFAULT;
2345 input = peasycap->frame_buffer[peasycap->frame_read][0].input;
2346 if (0x08 & input) {
2347 JOM(8, "user is offered frame buffer %i, input %i\n", \
2348 peasycap->frame_read, (0x07 & input));
2349 } else {
2350 JOM(8, "user is offered frame buffer %i\n", \
2351 peasycap->frame_read);
2353 peasycap->frame_lock = 1;
2354 JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill);
2355 if (peasycap->frame_read == peasycap->frame_fill) {
2356 if (peasycap->frame_lock) {
2357 JOM(8, "WORRY: filling frame buffer " \
2358 "while offered to user\n");
2361 break;
2363 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2364 case VIDIOC_STREAMON: {
2365 int i;
2367 JOM(8, "VIDIOC_STREAMON\n");
2369 peasycap->isequence = 0;
2370 for (i = 0; i < 180; i++)
2371 peasycap->merit[i] = 0;
2372 if ((struct usb_device *)NULL == peasycap->pusb_device) {
2373 SAM("ERROR: peasycap->pusb_device is NULL\n");
2374 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2375 return -EFAULT;
2377 submit_video_urbs(peasycap);
2378 peasycap->video_idle = 0;
2379 peasycap->audio_idle = 0;
2380 peasycap->video_eof = 0;
2381 peasycap->audio_eof = 0;
2382 break;
2384 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2385 case VIDIOC_STREAMOFF: {
2386 JOM(8, "VIDIOC_STREAMOFF\n");
2388 if ((struct usb_device *)NULL == peasycap->pusb_device) {
2389 SAM("ERROR: peasycap->pusb_device is NULL\n");
2390 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2391 return -EFAULT;
2394 peasycap->video_idle = 1;
2395 peasycap->audio_idle = 1; peasycap->timeval0.tv_sec = 0;
2396 /*---------------------------------------------------------------------------*/
2398 * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND
2399 * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
2401 /*---------------------------------------------------------------------------*/
2402 JOM(8, "calling wake_up on wq_video and wq_audio\n");
2403 wake_up_interruptible(&(peasycap->wq_video));
2404 #if defined(EASYCAP_NEEDS_ALSA)
2405 if (NULL != peasycap->psubstream)
2406 snd_pcm_period_elapsed(peasycap->psubstream);
2407 #else
2408 wake_up_interruptible(&(peasycap->wq_audio));
2409 #endif /*EASYCAP_NEEDS_ALSA*/
2410 /*---------------------------------------------------------------------------*/
2411 break;
2413 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2414 case VIDIOC_G_PARM: {
2415 struct v4l2_streamparm *pv4l2_streamparm;
2417 JOM(8, "VIDIOC_G_PARM\n");
2418 pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL);
2419 if (!pv4l2_streamparm) {
2420 SAM("ERROR: out of memory\n");
2421 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2422 return -ENOMEM;
2424 if (0 != copy_from_user(pv4l2_streamparm, (void __user *)arg, \
2425 sizeof(struct v4l2_streamparm))) {
2426 kfree(pv4l2_streamparm);
2427 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2428 return -EFAULT;
2431 if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
2432 kfree(pv4l2_streamparm);
2433 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2434 return -EINVAL;
2436 pv4l2_streamparm->parm.capture.capability = 0;
2437 pv4l2_streamparm->parm.capture.capturemode = 0;
2438 pv4l2_streamparm->parm.capture.timeperframe.numerator = 1;
2440 if (peasycap->fps) {
2441 pv4l2_streamparm->parm.capture.timeperframe.\
2442 denominator = peasycap->fps;
2443 } else {
2444 if (true == peasycap->ntsc) {
2445 pv4l2_streamparm->parm.capture.timeperframe.\
2446 denominator = 30;
2447 } else {
2448 pv4l2_streamparm->parm.capture.timeperframe.\
2449 denominator = 25;
2453 pv4l2_streamparm->parm.capture.readbuffers = \
2454 peasycap->frame_buffer_many;
2455 pv4l2_streamparm->parm.capture.extendedmode = 0;
2456 if (0 != copy_to_user((void __user *)arg, pv4l2_streamparm, \
2457 sizeof(struct v4l2_streamparm))) {
2458 kfree(pv4l2_streamparm);
2459 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2460 return -EFAULT;
2462 kfree(pv4l2_streamparm);
2463 break;
2465 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2466 case VIDIOC_S_PARM: {
2467 JOM(8, "VIDIOC_S_PARM unsupported\n");
2468 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2469 return -EINVAL;
2471 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2472 case VIDIOC_G_AUDIO: {
2473 JOM(8, "VIDIOC_G_AUDIO unsupported\n");
2474 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2475 return -EINVAL;
2477 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2478 case VIDIOC_S_AUDIO: {
2479 JOM(8, "VIDIOC_S_AUDIO unsupported\n");
2480 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2481 return -EINVAL;
2483 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2484 case VIDIOC_S_TUNER: {
2485 JOM(8, "VIDIOC_S_TUNER unsupported\n");
2486 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2487 return -EINVAL;
2489 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2490 case VIDIOC_G_FBUF:
2491 case VIDIOC_S_FBUF:
2492 case VIDIOC_OVERLAY: {
2493 JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n");
2494 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2495 return -EINVAL;
2497 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2498 case VIDIOC_G_TUNER: {
2499 JOM(8, "VIDIOC_G_TUNER unsupported\n");
2500 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2501 return -EINVAL;
2503 case VIDIOC_G_FREQUENCY:
2504 case VIDIOC_S_FREQUENCY: {
2505 JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n");
2506 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2507 return -EINVAL;
2509 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2510 default: {
2511 JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd);
2512 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2513 return -ENOIOCTLCMD;
2516 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
2517 JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd);
2518 return 0;
2520 /*****************************************************************************/
2521 #if !defined(EASYCAP_NEEDS_ALSA)
2522 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
2523 #if ((defined(EASYCAP_IS_VIDEODEV_CLIENT)) || \
2524 (defined(EASYCAP_NEEDS_UNLOCKED_IOCTL)))
2525 long
2526 easyoss_ioctl_noinode(struct file *file, unsigned int cmd, unsigned long arg) {
2527 return (long)easyoss_ioctl((struct inode *)NULL, file, cmd, arg);
2529 #endif /*EASYCAP_IS_VIDEODEV_CLIENT||EASYCAP_NEEDS_UNLOCKED_IOCTL*/
2530 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
2531 /*---------------------------------------------------------------------------*/
2533 easyoss_ioctl(struct inode *inode, struct file *file,
2534 unsigned int cmd, unsigned long arg)
2536 struct easycap *peasycap;
2537 struct usb_device *p;
2538 int kd;
2540 if (NULL == file) {
2541 SAY("ERROR: file is NULL\n");
2542 return -ERESTARTSYS;
2544 peasycap = file->private_data;
2545 if (NULL == peasycap) {
2546 SAY("ERROR: peasycap is NULL.\n");
2547 return -EFAULT;
2549 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
2550 SAY("ERROR: bad peasycap\n");
2551 return -EFAULT;
2553 p = peasycap->pusb_device;
2554 if (NULL == p) {
2555 SAM("ERROR: peasycap->pusb_device is NULL\n");
2556 return -EFAULT;
2558 kd = isdongle(peasycap);
2559 if (0 <= kd && DONGLE_MANY > kd) {
2560 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
2561 SAY("ERROR: cannot lock "
2562 "easycapdc60_dongle[%i].mutex_audio\n", kd);
2563 return -ERESTARTSYS;
2565 JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
2566 /*---------------------------------------------------------------------------*/
2568 * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
2569 * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
2570 * IF NECESSARY, BAIL OUT.
2572 /*---------------------------------------------------------------------------*/
2573 if (kd != isdongle(peasycap))
2574 return -ERESTARTSYS;
2575 if (NULL == file) {
2576 SAY("ERROR: file is NULL\n");
2577 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2578 return -ERESTARTSYS;
2580 peasycap = file->private_data;
2581 if (NULL == peasycap) {
2582 SAY("ERROR: peasycap is NULL\n");
2583 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2584 return -ERESTARTSYS;
2586 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
2587 SAY("ERROR: bad peasycap\n");
2588 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2589 return -EFAULT;
2591 p = peasycap->pusb_device;
2592 if (NULL == peasycap->pusb_device) {
2593 SAM("ERROR: peasycap->pusb_device is NULL\n");
2594 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2595 return -ERESTARTSYS;
2597 } else {
2598 /*---------------------------------------------------------------------------*/
2600 * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
2601 * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
2603 /*---------------------------------------------------------------------------*/
2604 return -ERESTARTSYS;
2606 /*---------------------------------------------------------------------------*/
2607 switch (cmd) {
2608 case SNDCTL_DSP_GETCAPS: {
2609 int caps;
2610 JOM(8, "SNDCTL_DSP_GETCAPS\n");
2612 #if defined(UPSAMPLE)
2613 if (true == peasycap->microphone)
2614 caps = 0x04400000;
2615 else
2616 caps = 0x04400000;
2617 #else
2618 if (true == peasycap->microphone)
2619 caps = 0x02400000;
2620 else
2621 caps = 0x04400000;
2622 #endif /*UPSAMPLE*/
2624 if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) {
2625 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2626 return -EFAULT;
2628 break;
2630 case SNDCTL_DSP_GETFMTS: {
2631 int incoming;
2632 JOM(8, "SNDCTL_DSP_GETFMTS\n");
2634 #if defined(UPSAMPLE)
2635 if (true == peasycap->microphone)
2636 incoming = AFMT_S16_LE;
2637 else
2638 incoming = AFMT_S16_LE;
2639 #else
2640 if (true == peasycap->microphone)
2641 incoming = AFMT_S16_LE;
2642 else
2643 incoming = AFMT_S16_LE;
2644 #endif /*UPSAMPLE*/
2646 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
2647 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2648 return -EFAULT;
2650 break;
2652 case SNDCTL_DSP_SETFMT: {
2653 int incoming, outgoing;
2654 JOM(8, "SNDCTL_DSP_SETFMT\n");
2655 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
2656 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2657 return -EFAULT;
2659 JOM(8, "........... %i=incoming\n", incoming);
2661 #if defined(UPSAMPLE)
2662 if (true == peasycap->microphone)
2663 outgoing = AFMT_S16_LE;
2664 else
2665 outgoing = AFMT_S16_LE;
2666 #else
2667 if (true == peasycap->microphone)
2668 outgoing = AFMT_S16_LE;
2669 else
2670 outgoing = AFMT_S16_LE;
2671 #endif /*UPSAMPLE*/
2673 if (incoming != outgoing) {
2674 JOM(8, "........... %i=outgoing\n", outgoing);
2675 JOM(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
2676 JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8);
2677 if (0 != copy_to_user((void __user *)arg, &outgoing, \
2678 sizeof(int))) {
2679 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2680 return -EFAULT;
2682 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2683 return -EINVAL ;
2685 break;
2687 case SNDCTL_DSP_STEREO: {
2688 int incoming;
2689 JOM(8, "SNDCTL_DSP_STEREO\n");
2690 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
2691 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2692 return -EFAULT;
2694 JOM(8, "........... %i=incoming\n", incoming);
2696 #if defined(UPSAMPLE)
2697 if (true == peasycap->microphone)
2698 incoming = 1;
2699 else
2700 incoming = 1;
2701 #else
2702 if (true == peasycap->microphone)
2703 incoming = 0;
2704 else
2705 incoming = 1;
2706 #endif /*UPSAMPLE*/
2708 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
2709 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2710 return -EFAULT;
2712 break;
2714 case SNDCTL_DSP_SPEED: {
2715 int incoming;
2716 JOM(8, "SNDCTL_DSP_SPEED\n");
2717 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
2718 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2719 return -EFAULT;
2721 JOM(8, "........... %i=incoming\n", incoming);
2723 #if defined(UPSAMPLE)
2724 if (true == peasycap->microphone)
2725 incoming = 32000;
2726 else
2727 incoming = 48000;
2728 #else
2729 if (true == peasycap->microphone)
2730 incoming = 8000;
2731 else
2732 incoming = 48000;
2733 #endif /*UPSAMPLE*/
2735 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
2736 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2737 return -EFAULT;
2739 break;
2741 case SNDCTL_DSP_GETTRIGGER: {
2742 int incoming;
2743 JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
2744 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
2745 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2746 return -EFAULT;
2748 JOM(8, "........... %i=incoming\n", incoming);
2750 incoming = PCM_ENABLE_INPUT;
2751 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
2752 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2753 return -EFAULT;
2755 break;
2757 case SNDCTL_DSP_SETTRIGGER: {
2758 int incoming;
2759 JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
2760 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
2761 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2762 return -EFAULT;
2764 JOM(8, "........... %i=incoming\n", incoming);
2765 JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT " \
2766 "0x%x=PCM_ENABLE_OUTPUT\n", \
2767 PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
2772 break;
2774 case SNDCTL_DSP_GETBLKSIZE: {
2775 int incoming;
2776 JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
2777 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
2778 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2779 return -EFAULT;
2781 JOM(8, "........... %i=incoming\n", incoming);
2782 incoming = peasycap->audio_bytes_per_fragment;
2783 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
2784 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2785 return -EFAULT;
2787 break;
2789 case SNDCTL_DSP_GETISPACE: {
2790 struct audio_buf_info audio_buf_info;
2792 JOM(8, "SNDCTL_DSP_GETISPACE\n");
2794 audio_buf_info.bytes = peasycap->audio_bytes_per_fragment;
2795 audio_buf_info.fragments = 1;
2796 audio_buf_info.fragsize = 0;
2797 audio_buf_info.fragstotal = 0;
2799 if (0 != copy_to_user((void __user *)arg, &audio_buf_info, \
2800 sizeof(int))) {
2801 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2802 return -EFAULT;
2804 break;
2806 case 0x00005401:
2807 case 0x00005402:
2808 case 0x00005403:
2809 case 0x00005404:
2810 case 0x00005405:
2811 case 0x00005406: {
2812 JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
2813 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2814 return -ENOIOCTLCMD;
2816 default: {
2817 JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
2818 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2819 return -ENOIOCTLCMD;
2822 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
2823 return 0;
2825 #endif /*EASYCAP_NEEDS_ALSA*/
2826 /*****************************************************************************/