diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/staging/easycap/easycap_ioctl.c | |
parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) |
Diffstat (limited to 'drivers/staging/easycap/easycap_ioctl.c')
-rw-r--r-- | drivers/staging/easycap/easycap_ioctl.c | 2462 |
1 files changed, 2462 insertions, 0 deletions
diff --git a/drivers/staging/easycap/easycap_ioctl.c b/drivers/staging/easycap/easycap_ioctl.c new file mode 100644 index 00000000000..0accab97a7f --- /dev/null +++ b/drivers/staging/easycap/easycap_ioctl.c | |||
@@ -0,0 +1,2462 @@ | |||
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 <linux/version.h> | ||
29 | #include "easycap.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 | kill_video_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 | submit_video_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 | kill_video_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 | submit_video_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 | mood = 0x00FF & (unsigned int)peasycap->brightness; | ||
671 | if (!write_saa(peasycap->pusb_device, 0x0A, mood)) { | ||
672 | SAM("adjusting brightness to 0x%02X\n", mood); | ||
673 | return 0; | ||
674 | } else { | ||
675 | SAM("WARNING: failed to adjust brightness " | ||
676 | "to 0x%02X\n", mood); | ||
677 | return -ENOENT; | ||
678 | } | ||
679 | break; | ||
680 | } | ||
681 | i1++; | ||
682 | } | ||
683 | SAM("WARNING: failed to adjust brightness: control not found\n"); | ||
684 | return -ENOENT; | ||
685 | } | ||
686 | /*****************************************************************************/ | ||
687 | int adjust_contrast(struct easycap *peasycap, int value) | ||
688 | { | ||
689 | unsigned int mood; | ||
690 | int i1, k; | ||
691 | |||
692 | if (!peasycap) { | ||
693 | SAY("ERROR: peasycap is NULL\n"); | ||
694 | return -EFAULT; | ||
695 | } | ||
696 | if (!peasycap->pusb_device) { | ||
697 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
698 | return -EFAULT; | ||
699 | } | ||
700 | i1 = 0; | ||
701 | while (0xFFFFFFFF != easycap_control[i1].id) { | ||
702 | if (V4L2_CID_CONTRAST == easycap_control[i1].id) { | ||
703 | if ((easycap_control[i1].minimum > value) || | ||
704 | (easycap_control[i1].maximum < value)) | ||
705 | value = easycap_control[i1].default_value; | ||
706 | |||
707 | |||
708 | if ((easycap_control[i1].minimum <= peasycap->contrast) && | ||
709 | (easycap_control[i1].maximum >= peasycap->contrast)) { | ||
710 | if (peasycap->contrast == value) { | ||
711 | SAM("unchanged contrast at 0x%02X\n", value); | ||
712 | return 0; | ||
713 | } | ||
714 | } | ||
715 | peasycap->contrast = value; | ||
716 | for (k = 0; k < INPUT_MANY; k++) { | ||
717 | if (!peasycap->inputset[k].contrast_ok) | ||
718 | peasycap->inputset[k].contrast = peasycap->contrast; | ||
719 | } | ||
720 | |||
721 | if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { | ||
722 | peasycap->inputset[peasycap->input].contrast = | ||
723 | peasycap->contrast; | ||
724 | peasycap->inputset[peasycap->input].contrast_ok = 1; | ||
725 | } else | ||
726 | JOM(8, "%i=peasycap->input\n", peasycap->input); | ||
727 | |||
728 | mood = 0x00FF & (unsigned int) (peasycap->contrast - 128); | ||
729 | if (!write_saa(peasycap->pusb_device, 0x0B, mood)) { | ||
730 | SAM("adjusting contrast to 0x%02X\n", mood); | ||
731 | return 0; | ||
732 | } else { | ||
733 | SAM("WARNING: failed to adjust contrast to " | ||
734 | "0x%02X\n", mood); | ||
735 | return -ENOENT; | ||
736 | } | ||
737 | break; | ||
738 | } | ||
739 | i1++; | ||
740 | } | ||
741 | SAM("WARNING: failed to adjust contrast: control not found\n"); | ||
742 | return -ENOENT; | ||
743 | } | ||
744 | /*****************************************************************************/ | ||
745 | int adjust_saturation(struct easycap *peasycap, int value) | ||
746 | { | ||
747 | unsigned int mood; | ||
748 | int i1, k; | ||
749 | |||
750 | if (!peasycap) { | ||
751 | SAY("ERROR: peasycap is NULL\n"); | ||
752 | return -EFAULT; | ||
753 | } | ||
754 | if (!peasycap->pusb_device) { | ||
755 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
756 | return -EFAULT; | ||
757 | } | ||
758 | i1 = 0; | ||
759 | while (0xFFFFFFFF != easycap_control[i1].id) { | ||
760 | if (V4L2_CID_SATURATION == easycap_control[i1].id) { | ||
761 | if ((easycap_control[i1].minimum > value) || | ||
762 | (easycap_control[i1].maximum < value)) | ||
763 | value = easycap_control[i1].default_value; | ||
764 | |||
765 | |||
766 | if ((easycap_control[i1].minimum <= peasycap->saturation) && | ||
767 | (easycap_control[i1].maximum >= peasycap->saturation)) { | ||
768 | if (peasycap->saturation == value) { | ||
769 | SAM("unchanged saturation at 0x%02X\n", | ||
770 | value); | ||
771 | return 0; | ||
772 | } | ||
773 | } | ||
774 | peasycap->saturation = value; | ||
775 | for (k = 0; k < INPUT_MANY; k++) { | ||
776 | if (!peasycap->inputset[k].saturation_ok) | ||
777 | peasycap->inputset[k].saturation = | ||
778 | peasycap->saturation; | ||
779 | } | ||
780 | if ((0 <= peasycap->input) && (INPUT_MANY > peasycap->input)) { | ||
781 | peasycap->inputset[peasycap->input].saturation = | ||
782 | peasycap->saturation; | ||
783 | peasycap->inputset[peasycap->input].saturation_ok = 1; | ||
784 | } else | ||
785 | JOM(8, "%i=peasycap->input\n", peasycap->input); | ||
786 | mood = 0x00FF & (unsigned int) (peasycap->saturation - 128); | ||
787 | if (!write_saa(peasycap->pusb_device, 0x0C, mood)) { | ||
788 | SAM("adjusting saturation to 0x%02X\n", mood); | ||
789 | return 0; | ||
790 | } else { | ||
791 | SAM("WARNING: failed to adjust saturation to " | ||
792 | "0x%02X\n", mood); | ||
793 | return -ENOENT; | ||
794 | } | ||
795 | break; | ||
796 | } | ||
797 | i1++; | ||
798 | } | ||
799 | SAM("WARNING: failed to adjust saturation: control not found\n"); | ||
800 | return -ENOENT; | ||
801 | } | ||
802 | /*****************************************************************************/ | ||
803 | int adjust_hue(struct easycap *peasycap, int value) | ||
804 | { | ||
805 | unsigned int mood; | ||
806 | int i1, i2, k; | ||
807 | |||
808 | if (!peasycap) { | ||
809 | SAY("ERROR: peasycap is NULL\n"); | ||
810 | return -EFAULT; | ||
811 | } | ||
812 | if (!peasycap->pusb_device) { | ||
813 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
814 | return -EFAULT; | ||
815 | } | ||
816 | i1 = 0; | ||
817 | while (0xFFFFFFFF != easycap_control[i1].id) { | ||
818 | if (V4L2_CID_HUE == easycap_control[i1].id) { | ||
819 | if ((easycap_control[i1].minimum > value) || | ||
820 | (easycap_control[i1].maximum < value)) | ||
821 | value = easycap_control[i1].default_value; | ||
822 | |||
823 | if ((easycap_control[i1].minimum <= peasycap->hue) && | ||
824 | (easycap_control[i1].maximum >= peasycap->hue)) { | ||
825 | if (peasycap->hue == value) { | ||
826 | SAM("unchanged hue at 0x%02X\n", value); | ||
827 | return 0; | ||
828 | } | ||
829 | } | ||
830 | peasycap->hue = value; | ||
831 | for (k = 0; k < INPUT_MANY; k++) { | ||
832 | if (!peasycap->inputset[k].hue_ok) | ||
833 | peasycap->inputset[k].hue = peasycap->hue; | ||
834 | } | ||
835 | if (0 <= peasycap->input && INPUT_MANY > peasycap->input) { | ||
836 | peasycap->inputset[peasycap->input].hue = 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; | ||
848 | } | ||
849 | break; | ||
850 | } | ||
851 | i1++; | ||
852 | } | ||
853 | SAM("WARNING: failed to adjust hue: control not found\n"); | ||
854 | return -ENOENT; | ||
855 | } | ||
856 | /*****************************************************************************/ | ||
857 | int adjust_volume(struct easycap *peasycap, int value) | ||
858 | { | ||
859 | s8 mood; | ||
860 | int i1; | ||
861 | |||
862 | if (!peasycap) { | ||
863 | SAY("ERROR: peasycap is NULL\n"); | ||
864 | return -EFAULT; | ||
865 | } | ||
866 | if (!peasycap->pusb_device) { | ||
867 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
868 | return -EFAULT; | ||
869 | } | ||
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 | |||
877 | if ((easycap_control[i1].minimum <= peasycap->volume) && | ||
878 | (easycap_control[i1].maximum >= peasycap->volume)) { | ||
879 | if (peasycap->volume == value) { | ||
880 | SAM("unchanged volume at 0x%02X\n", value); | ||
881 | return 0; | ||
882 | } | ||
883 | } | ||
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; | ||
895 | } | ||
896 | break; | ||
897 | } | ||
898 | i1++; | ||
899 | } | ||
900 | SAM("WARNING: failed to adjust volume: control not found\n"); | ||
901 | return -ENOENT; | ||
902 | } | ||
903 | /*****************************************************************************/ | ||
904 | /*---------------------------------------------------------------------------*/ | ||
905 | /* | ||
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. | ||
913 | */ | ||
914 | /*---------------------------------------------------------------------------*/ | ||
915 | static int adjust_mute(struct easycap *peasycap, int value) | ||
916 | { | ||
917 | int i1; | ||
918 | |||
919 | if (!peasycap) { | ||
920 | SAY("ERROR: peasycap is NULL\n"); | ||
921 | return -EFAULT; | ||
922 | } | ||
923 | if (!peasycap->pusb_device) { | ||
924 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
925 | return -EFAULT; | ||
926 | } | ||
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; | ||
938 | } | ||
939 | default: { | ||
940 | peasycap->audio_idle = 0; | ||
941 | SAM("adjusting mute: %i=peasycap->audio_idle\n", | ||
942 | peasycap->audio_idle); | ||
943 | return 0; | ||
944 | } | ||
945 | } | ||
946 | break; | ||
947 | } | ||
948 | i1++; | ||
949 | } | ||
950 | SAM("WARNING: failed to adjust mute: control not found\n"); | ||
951 | return -ENOENT; | ||
952 | } | ||
953 | /*---------------------------------------------------------------------------*/ | ||
954 | long easycap_unlocked_ioctl(struct file *file, | ||
955 | unsigned int cmd, unsigned long arg) | ||
956 | { | ||
957 | struct easycap *peasycap; | ||
958 | struct usb_device *p; | ||
959 | int kd; | ||
960 | |||
961 | if (!file) { | ||
962 | SAY("ERROR: file is NULL\n"); | ||
963 | return -ERESTARTSYS; | ||
964 | } | ||
965 | peasycap = file->private_data; | ||
966 | if (!peasycap) { | ||
967 | SAY("ERROR: peasycap is NULL\n"); | ||
968 | return -1; | ||
969 | } | ||
970 | p = peasycap->pusb_device; | ||
971 | if (!p) { | ||
972 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
973 | return -EFAULT; | ||
974 | } | ||
975 | kd = isdongle(peasycap); | ||
976 | if (0 <= kd && DONGLE_MANY > kd) { | ||
977 | if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) { | ||
978 | SAY("ERROR: cannot lock " | ||
979 | "easycapdc60_dongle[%i].mutex_video\n", kd); | ||
980 | return -ERESTARTSYS; | ||
981 | } | ||
982 | JOM(4, "locked easycapdc60_dongle[%i].mutex_video\n", kd); | ||
983 | /*---------------------------------------------------------------------------*/ | ||
984 | /* | ||
985 | * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap, | ||
986 | * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL. | ||
987 | * IF NECESSARY, BAIL OUT. | ||
988 | */ | ||
989 | /*---------------------------------------------------------------------------*/ | ||
990 | if (kd != isdongle(peasycap)) | ||
991 | return -ERESTARTSYS; | ||
992 | if (!file) { | ||
993 | SAY("ERROR: file is NULL\n"); | ||
994 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
995 | return -ERESTARTSYS; | ||
996 | } | ||
997 | peasycap = file->private_data; | ||
998 | if (!peasycap) { | ||
999 | SAY("ERROR: peasycap is NULL\n"); | ||
1000 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1001 | return -ERESTARTSYS; | ||
1002 | } | ||
1003 | if (!peasycap->pusb_device) { | ||
1004 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
1005 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1006 | return -ERESTARTSYS; | ||
1007 | } | ||
1008 | } else { | ||
1009 | /*---------------------------------------------------------------------------*/ | ||
1010 | /* | ||
1011 | * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE | ||
1012 | * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT. | ||
1013 | */ | ||
1014 | /*---------------------------------------------------------------------------*/ | ||
1015 | return -ERESTARTSYS; | ||
1016 | } | ||
1017 | /*---------------------------------------------------------------------------*/ | ||
1018 | switch (cmd) { | ||
1019 | case VIDIOC_QUERYCAP: { | ||
1020 | struct v4l2_capability v4l2_capability; | ||
1021 | char version[16], *p1, *p2; | ||
1022 | int i, rc, k[3]; | ||
1023 | long lng; | ||
1024 | |||
1025 | JOM(8, "VIDIOC_QUERYCAP\n"); | ||
1026 | |||
1027 | if (16 <= strlen(EASYCAP_DRIVER_VERSION)) { | ||
1028 | SAM("ERROR: bad driver version string\n"); | ||
1029 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1030 | return -EINVAL; | ||
1031 | } | ||
1032 | strcpy(&version[0], EASYCAP_DRIVER_VERSION); | ||
1033 | for (i = 0; i < 3; i++) | ||
1034 | k[i] = 0; | ||
1035 | p2 = &version[0]; | ||
1036 | i = 0; | ||
1037 | while (*p2) { | ||
1038 | p1 = p2; | ||
1039 | while (*p2 && ('.' != *p2)) | ||
1040 | p2++; | ||
1041 | if (*p2) | ||
1042 | *p2++ = 0; | ||
1043 | if (3 > i) { | ||
1044 | rc = (int) strict_strtol(p1, 10, &lng); | ||
1045 | if (rc) { | ||
1046 | SAM("ERROR: %i=strict_strtol(%s,.,,)\n", | ||
1047 | rc, p1); | ||
1048 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1049 | return -EINVAL; | ||
1050 | } | ||
1051 | k[i] = (int)lng; | ||
1052 | } | ||
1053 | i++; | ||
1054 | } | ||
1055 | |||
1056 | memset(&v4l2_capability, 0, sizeof(struct v4l2_capability)); | ||
1057 | strlcpy(&v4l2_capability.driver[0], | ||
1058 | "easycap", sizeof(v4l2_capability.driver)); | ||
1059 | |||
1060 | v4l2_capability.capabilities = V4L2_CAP_VIDEO_CAPTURE | | ||
1061 | V4L2_CAP_STREAMING | | ||
1062 | V4L2_CAP_AUDIO | | ||
1063 | V4L2_CAP_READWRITE; | ||
1064 | |||
1065 | v4l2_capability.version = KERNEL_VERSION(k[0], k[1], k[2]); | ||
1066 | JOM(8, "v4l2_capability.version=(%i,%i,%i)\n", k[0], k[1], k[2]); | ||
1067 | |||
1068 | strlcpy(&v4l2_capability.card[0], | ||
1069 | "EasyCAP DC60", sizeof(v4l2_capability.card)); | ||
1070 | |||
1071 | if (usb_make_path(peasycap->pusb_device, | ||
1072 | &v4l2_capability.bus_info[0], | ||
1073 | sizeof(v4l2_capability.bus_info)) < 0) { | ||
1074 | |||
1075 | strlcpy(&v4l2_capability.bus_info[0], "EasyCAP bus_info", | ||
1076 | sizeof(v4l2_capability.bus_info)); | ||
1077 | JOM(8, "%s=v4l2_capability.bus_info\n", | ||
1078 | &v4l2_capability.bus_info[0]); | ||
1079 | } | ||
1080 | if (copy_to_user((void __user *)arg, &v4l2_capability, | ||
1081 | sizeof(struct v4l2_capability))) { | ||
1082 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1083 | return -EFAULT; | ||
1084 | } | ||
1085 | break; | ||
1086 | } | ||
1087 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1088 | case VIDIOC_ENUMINPUT: { | ||
1089 | struct v4l2_input v4l2_input; | ||
1090 | u32 index; | ||
1091 | |||
1092 | JOM(8, "VIDIOC_ENUMINPUT\n"); | ||
1093 | |||
1094 | if (copy_from_user(&v4l2_input, (void __user *)arg, | ||
1095 | sizeof(struct v4l2_input))) { | ||
1096 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1097 | return -EFAULT; | ||
1098 | } | ||
1099 | |||
1100 | index = v4l2_input.index; | ||
1101 | memset(&v4l2_input, 0, sizeof(struct v4l2_input)); | ||
1102 | |||
1103 | switch (index) { | ||
1104 | case 0: { | ||
1105 | v4l2_input.index = index; | ||
1106 | strcpy(&v4l2_input.name[0], "CVBS0"); | ||
1107 | v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; | ||
1108 | v4l2_input.audioset = 0x01; | ||
1109 | v4l2_input.tuner = 0; | ||
1110 | v4l2_input.std = V4L2_STD_PAL | | ||
1111 | V4L2_STD_SECAM | | ||
1112 | V4L2_STD_NTSC ; | ||
1113 | v4l2_input.status = 0; | ||
1114 | JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); | ||
1115 | break; | ||
1116 | } | ||
1117 | case 1: { | ||
1118 | v4l2_input.index = index; | ||
1119 | strcpy(&v4l2_input.name[0], "CVBS1"); | ||
1120 | v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; | ||
1121 | v4l2_input.audioset = 0x01; | ||
1122 | v4l2_input.tuner = 0; | ||
1123 | v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | | ||
1124 | V4L2_STD_NTSC; | ||
1125 | v4l2_input.status = 0; | ||
1126 | JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); | ||
1127 | break; | ||
1128 | } | ||
1129 | case 2: { | ||
1130 | v4l2_input.index = index; | ||
1131 | strcpy(&v4l2_input.name[0], "CVBS2"); | ||
1132 | v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; | ||
1133 | v4l2_input.audioset = 0x01; | ||
1134 | v4l2_input.tuner = 0; | ||
1135 | v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | | ||
1136 | V4L2_STD_NTSC ; | ||
1137 | v4l2_input.status = 0; | ||
1138 | JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); | ||
1139 | break; | ||
1140 | } | ||
1141 | case 3: { | ||
1142 | v4l2_input.index = index; | ||
1143 | strcpy(&v4l2_input.name[0], "CVBS3"); | ||
1144 | v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; | ||
1145 | v4l2_input.audioset = 0x01; | ||
1146 | v4l2_input.tuner = 0; | ||
1147 | v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | | ||
1148 | V4L2_STD_NTSC ; | ||
1149 | v4l2_input.status = 0; | ||
1150 | JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); | ||
1151 | break; | ||
1152 | } | ||
1153 | case 4: { | ||
1154 | v4l2_input.index = index; | ||
1155 | strcpy(&v4l2_input.name[0], "CVBS4"); | ||
1156 | v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; | ||
1157 | v4l2_input.audioset = 0x01; | ||
1158 | v4l2_input.tuner = 0; | ||
1159 | v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | | ||
1160 | V4L2_STD_NTSC ; | ||
1161 | v4l2_input.status = 0; | ||
1162 | JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); | ||
1163 | break; | ||
1164 | } | ||
1165 | case 5: { | ||
1166 | v4l2_input.index = index; | ||
1167 | strcpy(&v4l2_input.name[0], "S-VIDEO"); | ||
1168 | v4l2_input.type = V4L2_INPUT_TYPE_CAMERA; | ||
1169 | v4l2_input.audioset = 0x01; | ||
1170 | v4l2_input.tuner = 0; | ||
1171 | v4l2_input.std = V4L2_STD_PAL | V4L2_STD_SECAM | | ||
1172 | V4L2_STD_NTSC ; | ||
1173 | v4l2_input.status = 0; | ||
1174 | JOM(8, "%i=index: %s\n", index, &v4l2_input.name[0]); | ||
1175 | break; | ||
1176 | } | ||
1177 | default: { | ||
1178 | JOM(8, "%i=index: exhausts inputs\n", index); | ||
1179 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1180 | return -EINVAL; | ||
1181 | } | ||
1182 | } | ||
1183 | |||
1184 | if (copy_to_user((void __user *)arg, &v4l2_input, | ||
1185 | sizeof(struct v4l2_input))) { | ||
1186 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1187 | return -EFAULT; | ||
1188 | } | ||
1189 | break; | ||
1190 | } | ||
1191 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1192 | case VIDIOC_G_INPUT: { | ||
1193 | u32 index; | ||
1194 | |||
1195 | JOM(8, "VIDIOC_G_INPUT\n"); | ||
1196 | index = (u32)peasycap->input; | ||
1197 | JOM(8, "user is told: %i\n", index); | ||
1198 | if (copy_to_user((void __user *)arg, &index, sizeof(u32))) { | ||
1199 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1200 | return -EFAULT; | ||
1201 | } | ||
1202 | break; | ||
1203 | } | ||
1204 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1205 | case VIDIOC_S_INPUT: | ||
1206 | { | ||
1207 | u32 index; | ||
1208 | int rc; | ||
1209 | |||
1210 | JOM(8, "VIDIOC_S_INPUT\n"); | ||
1211 | |||
1212 | if (0 != copy_from_user(&index, (void __user *)arg, sizeof(u32))) { | ||
1213 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1214 | return -EFAULT; | ||
1215 | } | ||
1216 | |||
1217 | JOM(8, "user requests input %i\n", index); | ||
1218 | |||
1219 | if ((int)index == peasycap->input) { | ||
1220 | SAM("requested input already in effect\n"); | ||
1221 | break; | ||
1222 | } | ||
1223 | |||
1224 | if ((0 > index) || (INPUT_MANY <= index)) { | ||
1225 | JOM(8, "ERROR: bad requested input: %i\n", index); | ||
1226 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1227 | return -EINVAL; | ||
1228 | } | ||
1229 | |||
1230 | rc = newinput(peasycap, (int)index); | ||
1231 | if (0 == rc) { | ||
1232 | JOM(8, "newinput(.,%i) OK\n", (int)index); | ||
1233 | } else { | ||
1234 | SAM("ERROR: newinput(.,%i) returned %i\n", (int)index, rc); | ||
1235 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1236 | return -EFAULT; | ||
1237 | } | ||
1238 | break; | ||
1239 | } | ||
1240 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1241 | case VIDIOC_ENUMAUDIO: { | ||
1242 | JOM(8, "VIDIOC_ENUMAUDIO\n"); | ||
1243 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1244 | return -EINVAL; | ||
1245 | } | ||
1246 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1247 | case VIDIOC_ENUMAUDOUT: { | ||
1248 | struct v4l2_audioout v4l2_audioout; | ||
1249 | |||
1250 | JOM(8, "VIDIOC_ENUMAUDOUT\n"); | ||
1251 | |||
1252 | if (copy_from_user(&v4l2_audioout, (void __user *)arg, | ||
1253 | sizeof(struct v4l2_audioout))) { | ||
1254 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1255 | return -EFAULT; | ||
1256 | } | ||
1257 | |||
1258 | if (0 != v4l2_audioout.index) { | ||
1259 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1260 | return -EINVAL; | ||
1261 | } | ||
1262 | memset(&v4l2_audioout, 0, sizeof(struct v4l2_audioout)); | ||
1263 | v4l2_audioout.index = 0; | ||
1264 | strcpy(&v4l2_audioout.name[0], "Soundtrack"); | ||
1265 | |||
1266 | if (copy_to_user((void __user *)arg, &v4l2_audioout, | ||
1267 | sizeof(struct v4l2_audioout))) { | ||
1268 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1269 | return -EFAULT; | ||
1270 | } | ||
1271 | break; | ||
1272 | } | ||
1273 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1274 | case VIDIOC_QUERYCTRL: { | ||
1275 | int i1; | ||
1276 | struct v4l2_queryctrl v4l2_queryctrl; | ||
1277 | |||
1278 | JOM(8, "VIDIOC_QUERYCTRL\n"); | ||
1279 | |||
1280 | if (0 != copy_from_user(&v4l2_queryctrl, (void __user *)arg, | ||
1281 | sizeof(struct v4l2_queryctrl))) { | ||
1282 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1283 | return -EFAULT; | ||
1284 | } | ||
1285 | |||
1286 | i1 = 0; | ||
1287 | while (0xFFFFFFFF != easycap_control[i1].id) { | ||
1288 | if (easycap_control[i1].id == v4l2_queryctrl.id) { | ||
1289 | JOM(8, "VIDIOC_QUERYCTRL %s=easycap_control[%i]" | ||
1290 | ".name\n", &easycap_control[i1].name[0], i1); | ||
1291 | memcpy(&v4l2_queryctrl, &easycap_control[i1], | ||
1292 | sizeof(struct v4l2_queryctrl)); | ||
1293 | break; | ||
1294 | } | ||
1295 | i1++; | ||
1296 | } | ||
1297 | if (0xFFFFFFFF == easycap_control[i1].id) { | ||
1298 | JOM(8, "%i=index: exhausts controls\n", i1); | ||
1299 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1300 | return -EINVAL; | ||
1301 | } | ||
1302 | if (copy_to_user((void __user *)arg, &v4l2_queryctrl, | ||
1303 | sizeof(struct v4l2_queryctrl))) { | ||
1304 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1305 | return -EFAULT; | ||
1306 | } | ||
1307 | break; | ||
1308 | } | ||
1309 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1310 | case VIDIOC_QUERYMENU: { | ||
1311 | JOM(8, "VIDIOC_QUERYMENU unsupported\n"); | ||
1312 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1316 | case VIDIOC_G_CTRL: { | ||
1317 | struct v4l2_control *pv4l2_control; | ||
1318 | |||
1319 | JOM(8, "VIDIOC_G_CTRL\n"); | ||
1320 | pv4l2_control = kzalloc(sizeof(struct v4l2_control), GFP_KERNEL); | ||
1321 | if (!pv4l2_control) { | ||
1322 | SAM("ERROR: out of memory\n"); | ||
1323 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1324 | return -ENOMEM; | ||
1325 | } | ||
1326 | if (0 != copy_from_user(pv4l2_control, (void __user *)arg, | ||
1327 | sizeof(struct v4l2_control))) { | ||
1328 | kfree(pv4l2_control); | ||
1329 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1330 | return -EFAULT; | ||
1331 | } | ||
1332 | |||
1333 | switch (pv4l2_control->id) { | ||
1334 | case V4L2_CID_BRIGHTNESS: { | ||
1335 | pv4l2_control->value = peasycap->brightness; | ||
1336 | JOM(8, "user enquires brightness: %i\n", pv4l2_control->value); | ||
1337 | break; | ||
1338 | } | ||
1339 | case V4L2_CID_CONTRAST: { | ||
1340 | pv4l2_control->value = peasycap->contrast; | ||
1341 | JOM(8, "user enquires contrast: %i\n", pv4l2_control->value); | ||
1342 | break; | ||
1343 | } | ||
1344 | case V4L2_CID_SATURATION: { | ||
1345 | pv4l2_control->value = peasycap->saturation; | ||
1346 | JOM(8, "user enquires saturation: %i\n", pv4l2_control->value); | ||
1347 | break; | ||
1348 | } | ||
1349 | case V4L2_CID_HUE: { | ||
1350 | pv4l2_control->value = peasycap->hue; | ||
1351 | JOM(8, "user enquires hue: %i\n", pv4l2_control->value); | ||
1352 | break; | ||
1353 | } | ||
1354 | case V4L2_CID_AUDIO_VOLUME: { | ||
1355 | pv4l2_control->value = peasycap->volume; | ||
1356 | JOM(8, "user enquires volume: %i\n", pv4l2_control->value); | ||
1357 | break; | ||
1358 | } | ||
1359 | case V4L2_CID_AUDIO_MUTE: { | ||
1360 | if (1 == peasycap->mute) | ||
1361 | pv4l2_control->value = true; | ||
1362 | else | ||
1363 | pv4l2_control->value = false; | ||
1364 | JOM(8, "user enquires mute: %i\n", pv4l2_control->value); | ||
1365 | break; | ||
1366 | } | ||
1367 | default: { | ||
1368 | SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", | ||
1369 | pv4l2_control->id); | ||
1370 | kfree(pv4l2_control); | ||
1371 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1372 | return -EINVAL; | ||
1373 | } | ||
1374 | } | ||
1375 | if (copy_to_user((void __user *)arg, pv4l2_control, | ||
1376 | sizeof(struct v4l2_control))) { | ||
1377 | kfree(pv4l2_control); | ||
1378 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1379 | return -EFAULT; | ||
1380 | } | ||
1381 | kfree(pv4l2_control); | ||
1382 | break; | ||
1383 | } | ||
1384 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1385 | case VIDIOC_S_CTRL: { | ||
1386 | struct v4l2_control v4l2_control; | ||
1387 | |||
1388 | JOM(8, "VIDIOC_S_CTRL\n"); | ||
1389 | |||
1390 | if (0 != copy_from_user(&v4l2_control, (void __user *)arg, | ||
1391 | sizeof(struct v4l2_control))) { | ||
1392 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1393 | return -EFAULT; | ||
1394 | } | ||
1395 | |||
1396 | switch (v4l2_control.id) { | ||
1397 | case V4L2_CID_BRIGHTNESS: { | ||
1398 | JOM(8, "user requests brightness %i\n", v4l2_control.value); | ||
1399 | if (0 != adjust_brightness(peasycap, v4l2_control.value)) | ||
1400 | ; | ||
1401 | break; | ||
1402 | } | ||
1403 | case V4L2_CID_CONTRAST: { | ||
1404 | JOM(8, "user requests contrast %i\n", v4l2_control.value); | ||
1405 | if (0 != adjust_contrast(peasycap, v4l2_control.value)) | ||
1406 | ; | ||
1407 | break; | ||
1408 | } | ||
1409 | case V4L2_CID_SATURATION: { | ||
1410 | JOM(8, "user requests saturation %i\n", v4l2_control.value); | ||
1411 | if (0 != adjust_saturation(peasycap, v4l2_control.value)) | ||
1412 | ; | ||
1413 | break; | ||
1414 | } | ||
1415 | case V4L2_CID_HUE: { | ||
1416 | JOM(8, "user requests hue %i\n", v4l2_control.value); | ||
1417 | if (0 != adjust_hue(peasycap, v4l2_control.value)) | ||
1418 | ; | ||
1419 | break; | ||
1420 | } | ||
1421 | case V4L2_CID_AUDIO_VOLUME: { | ||
1422 | JOM(8, "user requests volume %i\n", v4l2_control.value); | ||
1423 | if (0 != adjust_volume(peasycap, v4l2_control.value)) | ||
1424 | ; | ||
1425 | break; | ||
1426 | } | ||
1427 | case V4L2_CID_AUDIO_MUTE: { | ||
1428 | int mute; | ||
1429 | |||
1430 | JOM(8, "user requests mute %i\n", v4l2_control.value); | ||
1431 | if (v4l2_control.value) | ||
1432 | mute = 1; | ||
1433 | else | ||
1434 | mute = 0; | ||
1435 | |||
1436 | if (0 != adjust_mute(peasycap, mute)) | ||
1437 | SAM("WARNING: failed to adjust mute to %i\n", mute); | ||
1438 | break; | ||
1439 | } | ||
1440 | default: { | ||
1441 | SAM("ERROR: unknown V4L2 control: 0x%08X=id\n", | ||
1442 | v4l2_control.id); | ||
1443 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1444 | return -EINVAL; | ||
1445 | } | ||
1446 | } | ||
1447 | break; | ||
1448 | } | ||
1449 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1450 | case VIDIOC_S_EXT_CTRLS: { | ||
1451 | JOM(8, "VIDIOC_S_EXT_CTRLS unsupported\n"); | ||
1452 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1453 | return -EINVAL; | ||
1454 | } | ||
1455 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1456 | case VIDIOC_ENUM_FMT: { | ||
1457 | u32 index; | ||
1458 | struct v4l2_fmtdesc v4l2_fmtdesc; | ||
1459 | |||
1460 | JOM(8, "VIDIOC_ENUM_FMT\n"); | ||
1461 | |||
1462 | if (0 != copy_from_user(&v4l2_fmtdesc, (void __user *)arg, | ||
1463 | sizeof(struct v4l2_fmtdesc))) { | ||
1464 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1465 | return -EFAULT; | ||
1466 | } | ||
1467 | |||
1468 | index = v4l2_fmtdesc.index; | ||
1469 | memset(&v4l2_fmtdesc, 0, sizeof(struct v4l2_fmtdesc)); | ||
1470 | |||
1471 | v4l2_fmtdesc.index = index; | ||
1472 | v4l2_fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1473 | |||
1474 | switch (index) { | ||
1475 | case 0: { | ||
1476 | v4l2_fmtdesc.flags = 0; | ||
1477 | strcpy(&v4l2_fmtdesc.description[0], "uyvy"); | ||
1478 | v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_UYVY; | ||
1479 | JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); | ||
1480 | break; | ||
1481 | } | ||
1482 | case 1: { | ||
1483 | v4l2_fmtdesc.flags = 0; | ||
1484 | strcpy(&v4l2_fmtdesc.description[0], "yuy2"); | ||
1485 | v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_YUYV; | ||
1486 | JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); | ||
1487 | break; | ||
1488 | } | ||
1489 | case 2: { | ||
1490 | v4l2_fmtdesc.flags = 0; | ||
1491 | strcpy(&v4l2_fmtdesc.description[0], "rgb24"); | ||
1492 | v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB24; | ||
1493 | JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); | ||
1494 | break; | ||
1495 | } | ||
1496 | case 3: { | ||
1497 | v4l2_fmtdesc.flags = 0; | ||
1498 | strcpy(&v4l2_fmtdesc.description[0], "rgb32"); | ||
1499 | v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_RGB32; | ||
1500 | JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); | ||
1501 | break; | ||
1502 | } | ||
1503 | case 4: { | ||
1504 | v4l2_fmtdesc.flags = 0; | ||
1505 | strcpy(&v4l2_fmtdesc.description[0], "bgr24"); | ||
1506 | v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR24; | ||
1507 | JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); | ||
1508 | break; | ||
1509 | } | ||
1510 | case 5: { | ||
1511 | v4l2_fmtdesc.flags = 0; | ||
1512 | strcpy(&v4l2_fmtdesc.description[0], "bgr32"); | ||
1513 | v4l2_fmtdesc.pixelformat = V4L2_PIX_FMT_BGR32; | ||
1514 | JOM(8, "%i=index: %s\n", index, &v4l2_fmtdesc.description[0]); | ||
1515 | break; | ||
1516 | } | ||
1517 | default: { | ||
1518 | JOM(8, "%i=index: exhausts formats\n", index); | ||
1519 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1520 | return -EINVAL; | ||
1521 | } | ||
1522 | } | ||
1523 | if (copy_to_user((void __user *)arg, &v4l2_fmtdesc, | ||
1524 | sizeof(struct v4l2_fmtdesc))) { | ||
1525 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1526 | return -EFAULT; | ||
1527 | } | ||
1528 | break; | ||
1529 | } | ||
1530 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1531 | /* | ||
1532 | * THE RESPONSE TO VIDIOC_ENUM_FRAMESIZES MUST BE CONDITIONED ON THE | ||
1533 | * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. | ||
1534 | */ | ||
1535 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1536 | case VIDIOC_ENUM_FRAMESIZES: { | ||
1537 | u32 index; | ||
1538 | struct v4l2_frmsizeenum v4l2_frmsizeenum; | ||
1539 | |||
1540 | JOM(8, "VIDIOC_ENUM_FRAMESIZES\n"); | ||
1541 | |||
1542 | if (0 != copy_from_user(&v4l2_frmsizeenum, (void __user *)arg, | ||
1543 | sizeof(struct v4l2_frmsizeenum))) { | ||
1544 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1545 | return -EFAULT; | ||
1546 | } | ||
1547 | |||
1548 | index = v4l2_frmsizeenum.index; | ||
1549 | |||
1550 | v4l2_frmsizeenum.type = (u32) V4L2_FRMSIZE_TYPE_DISCRETE; | ||
1551 | |||
1552 | if (peasycap->ntsc) { | ||
1553 | switch (index) { | ||
1554 | case 0: { | ||
1555 | v4l2_frmsizeenum.discrete.width = 640; | ||
1556 | v4l2_frmsizeenum.discrete.height = 480; | ||
1557 | JOM(8, "%i=index: %ix%i\n", index, | ||
1558 | (int)(v4l2_frmsizeenum. | ||
1559 | discrete.width), | ||
1560 | (int)(v4l2_frmsizeenum. | ||
1561 | discrete.height)); | ||
1562 | break; | ||
1563 | } | ||
1564 | case 1: { | ||
1565 | v4l2_frmsizeenum.discrete.width = 320; | ||
1566 | v4l2_frmsizeenum.discrete.height = 240; | ||
1567 | JOM(8, "%i=index: %ix%i\n", index, | ||
1568 | (int)(v4l2_frmsizeenum. | ||
1569 | discrete.width), | ||
1570 | (int)(v4l2_frmsizeenum. | ||
1571 | discrete.height)); | ||
1572 | break; | ||
1573 | } | ||
1574 | case 2: { | ||
1575 | v4l2_frmsizeenum.discrete.width = 720; | ||
1576 | v4l2_frmsizeenum.discrete.height = 480; | ||
1577 | JOM(8, "%i=index: %ix%i\n", index, | ||
1578 | (int)(v4l2_frmsizeenum. | ||
1579 | discrete.width), | ||
1580 | (int)(v4l2_frmsizeenum. | ||
1581 | discrete.height)); | ||
1582 | break; | ||
1583 | } | ||
1584 | case 3: { | ||
1585 | v4l2_frmsizeenum.discrete.width = 360; | ||
1586 | v4l2_frmsizeenum.discrete.height = 240; | ||
1587 | JOM(8, "%i=index: %ix%i\n", index, | ||
1588 | (int)(v4l2_frmsizeenum. | ||
1589 | discrete.width), | ||
1590 | (int)(v4l2_frmsizeenum. | ||
1591 | discrete.height)); | ||
1592 | break; | ||
1593 | } | ||
1594 | default: { | ||
1595 | JOM(8, "%i=index: exhausts framesizes\n", index); | ||
1596 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1597 | return -EINVAL; | ||
1598 | } | ||
1599 | } | ||
1600 | } else { | ||
1601 | switch (index) { | ||
1602 | case 0: { | ||
1603 | v4l2_frmsizeenum.discrete.width = 640; | ||
1604 | v4l2_frmsizeenum.discrete.height = 480; | ||
1605 | JOM(8, "%i=index: %ix%i\n", index, | ||
1606 | (int)(v4l2_frmsizeenum. | ||
1607 | discrete.width), | ||
1608 | (int)(v4l2_frmsizeenum. | ||
1609 | discrete.height)); | ||
1610 | break; | ||
1611 | } | ||
1612 | case 1: { | ||
1613 | v4l2_frmsizeenum.discrete.width = 320; | ||
1614 | v4l2_frmsizeenum.discrete.height = 240; | ||
1615 | JOM(8, "%i=index: %ix%i\n", index, | ||
1616 | (int)(v4l2_frmsizeenum. | ||
1617 | discrete.width), | ||
1618 | (int)(v4l2_frmsizeenum. | ||
1619 | discrete.height)); | ||
1620 | break; | ||
1621 | } | ||
1622 | case 2: { | ||
1623 | v4l2_frmsizeenum.discrete.width = 704; | ||
1624 | v4l2_frmsizeenum.discrete.height = 576; | ||
1625 | JOM(8, "%i=index: %ix%i\n", index, | ||
1626 | (int)(v4l2_frmsizeenum. | ||
1627 | discrete.width), | ||
1628 | (int)(v4l2_frmsizeenum. | ||
1629 | discrete.height)); | ||
1630 | break; | ||
1631 | } | ||
1632 | case 3: { | ||
1633 | v4l2_frmsizeenum.discrete.width = 720; | ||
1634 | v4l2_frmsizeenum.discrete.height = 576; | ||
1635 | JOM(8, "%i=index: %ix%i\n", index, | ||
1636 | (int)(v4l2_frmsizeenum. | ||
1637 | discrete.width), | ||
1638 | (int)(v4l2_frmsizeenum. | ||
1639 | discrete.height)); | ||
1640 | break; | ||
1641 | } | ||
1642 | case 4: { | ||
1643 | v4l2_frmsizeenum.discrete.width = 360; | ||
1644 | v4l2_frmsizeenum.discrete.height = 288; | ||
1645 | JOM(8, "%i=index: %ix%i\n", index, | ||
1646 | (int)(v4l2_frmsizeenum. | ||
1647 | discrete.width), | ||
1648 | (int)(v4l2_frmsizeenum. | ||
1649 | discrete.height)); | ||
1650 | break; | ||
1651 | } | ||
1652 | default: { | ||
1653 | JOM(8, "%i=index: exhausts framesizes\n", index); | ||
1654 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1655 | return -EINVAL; | ||
1656 | } | ||
1657 | } | ||
1658 | } | ||
1659 | if (copy_to_user((void __user *)arg, &v4l2_frmsizeenum, | ||
1660 | sizeof(struct v4l2_frmsizeenum))) { | ||
1661 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1662 | return -EFAULT; | ||
1663 | } | ||
1664 | break; | ||
1665 | } | ||
1666 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1667 | /* | ||
1668 | * THE RESPONSE TO VIDIOC_ENUM_FRAMEINTERVALS MUST BE CONDITIONED ON THE | ||
1669 | * THE CURRENT STANDARD, BECAUSE THAT IS WHAT gstreamer EXPECTS. BEWARE. | ||
1670 | */ | ||
1671 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1672 | case VIDIOC_ENUM_FRAMEINTERVALS: { | ||
1673 | u32 index; | ||
1674 | int denominator; | ||
1675 | struct v4l2_frmivalenum v4l2_frmivalenum; | ||
1676 | |||
1677 | JOM(8, "VIDIOC_ENUM_FRAMEINTERVALS\n"); | ||
1678 | |||
1679 | if (peasycap->fps) | ||
1680 | denominator = peasycap->fps; | ||
1681 | else { | ||
1682 | if (peasycap->ntsc) | ||
1683 | denominator = 30; | ||
1684 | else | ||
1685 | denominator = 25; | ||
1686 | } | ||
1687 | |||
1688 | if (0 != copy_from_user(&v4l2_frmivalenum, (void __user *)arg, | ||
1689 | sizeof(struct v4l2_frmivalenum))) { | ||
1690 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1691 | return -EFAULT; | ||
1692 | } | ||
1693 | |||
1694 | index = v4l2_frmivalenum.index; | ||
1695 | |||
1696 | v4l2_frmivalenum.type = (u32) V4L2_FRMIVAL_TYPE_DISCRETE; | ||
1697 | |||
1698 | switch (index) { | ||
1699 | case 0: { | ||
1700 | v4l2_frmivalenum.discrete.numerator = 1; | ||
1701 | v4l2_frmivalenum.discrete.denominator = denominator; | ||
1702 | JOM(8, "%i=index: %i/%i\n", index, | ||
1703 | (int)(v4l2_frmivalenum.discrete.numerator), | ||
1704 | (int)(v4l2_frmivalenum.discrete.denominator)); | ||
1705 | break; | ||
1706 | } | ||
1707 | case 1: { | ||
1708 | v4l2_frmivalenum.discrete.numerator = 1; | ||
1709 | v4l2_frmivalenum.discrete.denominator = denominator/5; | ||
1710 | JOM(8, "%i=index: %i/%i\n", index, | ||
1711 | (int)(v4l2_frmivalenum.discrete.numerator), | ||
1712 | (int)(v4l2_frmivalenum.discrete.denominator)); | ||
1713 | break; | ||
1714 | } | ||
1715 | default: { | ||
1716 | JOM(8, "%i=index: exhausts frameintervals\n", index); | ||
1717 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1718 | return -EINVAL; | ||
1719 | } | ||
1720 | } | ||
1721 | if (copy_to_user((void __user *)arg, &v4l2_frmivalenum, | ||
1722 | sizeof(struct v4l2_frmivalenum))) { | ||
1723 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1724 | return -EFAULT; | ||
1725 | } | ||
1726 | break; | ||
1727 | } | ||
1728 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1729 | case VIDIOC_G_FMT: { | ||
1730 | struct v4l2_format *pv4l2_format; | ||
1731 | struct v4l2_pix_format *pv4l2_pix_format; | ||
1732 | |||
1733 | JOM(8, "VIDIOC_G_FMT\n"); | ||
1734 | pv4l2_format = kzalloc(sizeof(struct v4l2_format), GFP_KERNEL); | ||
1735 | if (!pv4l2_format) { | ||
1736 | SAM("ERROR: out of memory\n"); | ||
1737 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1738 | return -ENOMEM; | ||
1739 | } | ||
1740 | pv4l2_pix_format = kzalloc(sizeof(struct v4l2_pix_format), GFP_KERNEL); | ||
1741 | if (!pv4l2_pix_format) { | ||
1742 | SAM("ERROR: out of memory\n"); | ||
1743 | kfree(pv4l2_format); | ||
1744 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1745 | return -ENOMEM; | ||
1746 | } | ||
1747 | if (0 != copy_from_user(pv4l2_format, (void __user *)arg, | ||
1748 | sizeof(struct v4l2_format))) { | ||
1749 | kfree(pv4l2_format); | ||
1750 | kfree(pv4l2_pix_format); | ||
1751 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1752 | return -EFAULT; | ||
1753 | } | ||
1754 | |||
1755 | if (pv4l2_format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
1756 | kfree(pv4l2_format); | ||
1757 | kfree(pv4l2_pix_format); | ||
1758 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1759 | return -EINVAL; | ||
1760 | } | ||
1761 | |||
1762 | memset(pv4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); | ||
1763 | pv4l2_format->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1764 | memcpy(&pv4l2_format->fmt.pix, | ||
1765 | &easycap_format[peasycap->format_offset] | ||
1766 | .v4l2_format.fmt.pix, sizeof(struct v4l2_pix_format)); | ||
1767 | JOM(8, "user is told: %s\n", | ||
1768 | &easycap_format[peasycap->format_offset].name[0]); | ||
1769 | |||
1770 | if (copy_to_user((void __user *)arg, pv4l2_format, | ||
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; | ||
1776 | } | ||
1777 | kfree(pv4l2_format); | ||
1778 | kfree(pv4l2_pix_format); | ||
1779 | break; | ||
1780 | } | ||
1781 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1782 | case VIDIOC_TRY_FMT: | ||
1783 | case VIDIOC_S_FMT: { | ||
1784 | struct v4l2_format v4l2_format; | ||
1785 | struct v4l2_pix_format v4l2_pix_format; | ||
1786 | bool try; | ||
1787 | int best_format; | ||
1788 | |||
1789 | if (VIDIOC_TRY_FMT == cmd) { | ||
1790 | JOM(8, "VIDIOC_TRY_FMT\n"); | ||
1791 | try = true; | ||
1792 | } else { | ||
1793 | JOM(8, "VIDIOC_S_FMT\n"); | ||
1794 | try = false; | ||
1795 | } | ||
1796 | |||
1797 | if (0 != copy_from_user(&v4l2_format, (void __user *)arg, | ||
1798 | sizeof(struct v4l2_format))) { | ||
1799 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1800 | return -EFAULT; | ||
1801 | } | ||
1802 | |||
1803 | best_format = adjust_format(peasycap, | ||
1804 | v4l2_format.fmt.pix.width, | ||
1805 | v4l2_format.fmt.pix.height, | ||
1806 | v4l2_format.fmt.pix.pixelformat, | ||
1807 | v4l2_format.fmt.pix.field, | ||
1808 | try); | ||
1809 | if (0 > best_format) { | ||
1810 | if (-EBUSY == best_format) { | ||
1811 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1812 | return -EBUSY; | ||
1813 | } | ||
1814 | JOM(8, "WARNING: adjust_format() returned %i\n", best_format); | ||
1815 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1816 | return -ENOENT; | ||
1817 | } | ||
1818 | /*...........................................................................*/ | ||
1819 | memset(&v4l2_pix_format, 0, sizeof(struct v4l2_pix_format)); | ||
1820 | v4l2_format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1821 | |||
1822 | memcpy(&(v4l2_format.fmt.pix), | ||
1823 | &(easycap_format[best_format].v4l2_format.fmt.pix), | ||
1824 | sizeof(v4l2_pix_format)); | ||
1825 | JOM(8, "user is told: %s\n", &easycap_format[best_format].name[0]); | ||
1826 | |||
1827 | if (copy_to_user((void __user *)arg, &v4l2_format, | ||
1828 | sizeof(struct v4l2_format))) { | ||
1829 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1830 | return -EFAULT; | ||
1831 | } | ||
1832 | break; | ||
1833 | } | ||
1834 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1835 | case VIDIOC_CROPCAP: { | ||
1836 | struct v4l2_cropcap v4l2_cropcap; | ||
1837 | |||
1838 | JOM(8, "VIDIOC_CROPCAP\n"); | ||
1839 | |||
1840 | if (0 != copy_from_user(&v4l2_cropcap, (void __user *)arg, | ||
1841 | sizeof(struct v4l2_cropcap))) { | ||
1842 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1843 | return -EFAULT; | ||
1844 | } | ||
1845 | |||
1846 | if (v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
1847 | JOM(8, "v4l2_cropcap.type != V4L2_BUF_TYPE_VIDEO_CAPTURE\n"); | ||
1848 | |||
1849 | memset(&v4l2_cropcap, 0, sizeof(struct v4l2_cropcap)); | ||
1850 | v4l2_cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1851 | v4l2_cropcap.bounds.left = 0; | ||
1852 | v4l2_cropcap.bounds.top = 0; | ||
1853 | v4l2_cropcap.bounds.width = peasycap->width; | ||
1854 | v4l2_cropcap.bounds.height = peasycap->height; | ||
1855 | v4l2_cropcap.defrect.left = 0; | ||
1856 | v4l2_cropcap.defrect.top = 0; | ||
1857 | v4l2_cropcap.defrect.width = peasycap->width; | ||
1858 | v4l2_cropcap.defrect.height = peasycap->height; | ||
1859 | v4l2_cropcap.pixelaspect.numerator = 1; | ||
1860 | v4l2_cropcap.pixelaspect.denominator = 1; | ||
1861 | |||
1862 | JOM(8, "user is told: %ix%i\n", peasycap->width, peasycap->height); | ||
1863 | |||
1864 | if (copy_to_user((void __user *)arg, &v4l2_cropcap, | ||
1865 | sizeof(struct v4l2_cropcap))) { | ||
1866 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1867 | return -EFAULT; | ||
1868 | } | ||
1869 | break; | ||
1870 | } | ||
1871 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1872 | case VIDIOC_G_CROP: | ||
1873 | case VIDIOC_S_CROP: { | ||
1874 | JOM(8, "VIDIOC_G_CROP|VIDIOC_S_CROP unsupported\n"); | ||
1875 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1876 | return -EINVAL; | ||
1877 | } | ||
1878 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1879 | case VIDIOC_QUERYSTD: { | ||
1880 | JOM(8, "VIDIOC_QUERYSTD: " | ||
1881 | "EasyCAP is incapable of detecting standard\n"); | ||
1882 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1883 | return -EINVAL; | ||
1884 | break; | ||
1885 | } | ||
1886 | /*-------------------------------------------------------------------*/ | ||
1887 | /* | ||
1888 | * THE MANIPULATIONS INVOLVING last0,last1,last2,last3 | ||
1889 | * CONSTITUTE A WORKAROUND * FOR WHAT APPEARS TO BE | ||
1890 | * A BUG IN 64-BIT mplayer. | ||
1891 | * NOT NEEDED, BUT HOPEFULLY HARMLESS, FOR 32-BIT mplayer. | ||
1892 | */ | ||
1893 | /*------------------------------------------------------------------*/ | ||
1894 | case VIDIOC_ENUMSTD: { | ||
1895 | int last0 = -1, last1 = -1, last2 = -1, last3 = -1; | ||
1896 | struct v4l2_standard v4l2_standard; | ||
1897 | u32 index; | ||
1898 | struct easycap_standard const *peasycap_standard; | ||
1899 | |||
1900 | JOM(8, "VIDIOC_ENUMSTD\n"); | ||
1901 | |||
1902 | if (0 != copy_from_user(&v4l2_standard, (void __user *)arg, | ||
1903 | sizeof(struct v4l2_standard))) { | ||
1904 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1905 | return -EFAULT; | ||
1906 | } | ||
1907 | index = v4l2_standard.index; | ||
1908 | |||
1909 | last3 = last2; | ||
1910 | last2 = last1; | ||
1911 | last1 = last0; | ||
1912 | last0 = index; | ||
1913 | if ((index == last3) && (index == last2) && | ||
1914 | (index == last1) && (index == last0)) { | ||
1915 | index++; | ||
1916 | last3 = last2; | ||
1917 | last2 = last1; | ||
1918 | last1 = last0; | ||
1919 | last0 = index; | ||
1920 | } | ||
1921 | |||
1922 | memset(&v4l2_standard, 0, sizeof(struct v4l2_standard)); | ||
1923 | |||
1924 | peasycap_standard = &easycap_standard[0]; | ||
1925 | while (0xFFFF != peasycap_standard->mask) { | ||
1926 | if ((int)(peasycap_standard - &easycap_standard[0]) == index) | ||
1927 | break; | ||
1928 | peasycap_standard++; | ||
1929 | } | ||
1930 | if (0xFFFF == peasycap_standard->mask) { | ||
1931 | JOM(8, "%i=index: exhausts standards\n", index); | ||
1932 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1933 | return -EINVAL; | ||
1934 | } | ||
1935 | JOM(8, "%i=index: %s\n", index, | ||
1936 | &(peasycap_standard->v4l2_standard.name[0])); | ||
1937 | memcpy(&v4l2_standard, &(peasycap_standard->v4l2_standard), | ||
1938 | sizeof(struct v4l2_standard)); | ||
1939 | |||
1940 | v4l2_standard.index = index; | ||
1941 | |||
1942 | if (copy_to_user((void __user *)arg, &v4l2_standard, | ||
1943 | sizeof(struct v4l2_standard))) { | ||
1944 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1945 | return -EFAULT; | ||
1946 | } | ||
1947 | break; | ||
1948 | } | ||
1949 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1950 | case VIDIOC_G_STD: { | ||
1951 | v4l2_std_id std_id; | ||
1952 | struct easycap_standard const *peasycap_standard; | ||
1953 | |||
1954 | JOM(8, "VIDIOC_G_STD\n"); | ||
1955 | |||
1956 | if (0 > peasycap->standard_offset) { | ||
1957 | JOM(8, "%i=peasycap->standard_offset\n", | ||
1958 | peasycap->standard_offset); | ||
1959 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1960 | return -EBUSY; | ||
1961 | } | ||
1962 | |||
1963 | if (0 != copy_from_user(&std_id, (void __user *)arg, | ||
1964 | sizeof(v4l2_std_id))) { | ||
1965 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1966 | return -EFAULT; | ||
1967 | } | ||
1968 | |||
1969 | peasycap_standard = &easycap_standard[peasycap->standard_offset]; | ||
1970 | std_id = peasycap_standard->v4l2_standard.id; | ||
1971 | |||
1972 | JOM(8, "user is told: %s\n", | ||
1973 | &peasycap_standard->v4l2_standard.name[0]); | ||
1974 | |||
1975 | if (copy_to_user((void __user *)arg, &std_id, | ||
1976 | sizeof(v4l2_std_id))) { | ||
1977 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1978 | return -EFAULT; | ||
1979 | } | ||
1980 | break; | ||
1981 | } | ||
1982 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
1983 | case VIDIOC_S_STD: { | ||
1984 | v4l2_std_id std_id; | ||
1985 | int rc; | ||
1986 | |||
1987 | JOM(8, "VIDIOC_S_STD\n"); | ||
1988 | |||
1989 | if (0 != copy_from_user(&std_id, (void __user *)arg, | ||
1990 | sizeof(v4l2_std_id))) { | ||
1991 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
1992 | return -EFAULT; | ||
1993 | } | ||
1994 | |||
1995 | JOM(8, "User requests standard: 0x%08X%08X\n", | ||
1996 | (int)((std_id & (((v4l2_std_id)0xFFFFFFFF) << 32)) >> 32), | ||
1997 | (int)(std_id & ((v4l2_std_id)0xFFFFFFFF))); | ||
1998 | |||
1999 | rc = adjust_standard(peasycap, std_id); | ||
2000 | if (0 > rc) { | ||
2001 | JOM(8, "WARNING: adjust_standard() returned %i\n", rc); | ||
2002 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2003 | return -ENOENT; | ||
2004 | } | ||
2005 | break; | ||
2006 | } | ||
2007 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2008 | case VIDIOC_REQBUFS: { | ||
2009 | int nbuffers; | ||
2010 | struct v4l2_requestbuffers v4l2_requestbuffers; | ||
2011 | |||
2012 | JOM(8, "VIDIOC_REQBUFS\n"); | ||
2013 | |||
2014 | if (0 != copy_from_user(&v4l2_requestbuffers, | ||
2015 | (void __user *)arg, | ||
2016 | sizeof(struct v4l2_requestbuffers))) { | ||
2017 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2018 | return -EFAULT; | ||
2019 | } | ||
2020 | |||
2021 | if (v4l2_requestbuffers.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
2022 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2023 | return -EINVAL; | ||
2024 | } | ||
2025 | if (v4l2_requestbuffers.memory != V4L2_MEMORY_MMAP) { | ||
2026 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2027 | return -EINVAL; | ||
2028 | } | ||
2029 | nbuffers = v4l2_requestbuffers.count; | ||
2030 | JOM(8, " User requests %i buffers ...\n", nbuffers); | ||
2031 | if (nbuffers < 2) | ||
2032 | nbuffers = 2; | ||
2033 | if (nbuffers > FRAME_BUFFER_MANY) | ||
2034 | nbuffers = FRAME_BUFFER_MANY; | ||
2035 | if (v4l2_requestbuffers.count == nbuffers) { | ||
2036 | JOM(8, " ... agree to %i buffers\n", | ||
2037 | nbuffers); | ||
2038 | } else { | ||
2039 | JOM(8, " ... insist on %i buffers\n", | ||
2040 | nbuffers); | ||
2041 | v4l2_requestbuffers.count = nbuffers; | ||
2042 | } | ||
2043 | peasycap->frame_buffer_many = nbuffers; | ||
2044 | |||
2045 | if (copy_to_user((void __user *)arg, &v4l2_requestbuffers, | ||
2046 | sizeof(struct v4l2_requestbuffers))) { | ||
2047 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2048 | return -EFAULT; | ||
2049 | } | ||
2050 | break; | ||
2051 | } | ||
2052 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2053 | case VIDIOC_QUERYBUF: { | ||
2054 | u32 index; | ||
2055 | struct v4l2_buffer v4l2_buffer; | ||
2056 | |||
2057 | JOM(8, "VIDIOC_QUERYBUF\n"); | ||
2058 | |||
2059 | if (peasycap->video_eof) { | ||
2060 | JOM(8, "returning -EIO because %i=video_eof\n", | ||
2061 | peasycap->video_eof); | ||
2062 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2063 | return -EIO; | ||
2064 | } | ||
2065 | |||
2066 | if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, | ||
2067 | sizeof(struct v4l2_buffer))) { | ||
2068 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2069 | return -EFAULT; | ||
2070 | } | ||
2071 | |||
2072 | if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
2073 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2074 | return -EINVAL; | ||
2075 | } | ||
2076 | index = v4l2_buffer.index; | ||
2077 | if (index < 0 || index >= peasycap->frame_buffer_many) | ||
2078 | return -EINVAL; | ||
2079 | memset(&v4l2_buffer, 0, sizeof(struct v4l2_buffer)); | ||
2080 | v4l2_buffer.index = index; | ||
2081 | v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2082 | v4l2_buffer.bytesused = peasycap->frame_buffer_used; | ||
2083 | v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | | ||
2084 | peasycap->done[index] | | ||
2085 | peasycap->queued[index]; | ||
2086 | v4l2_buffer.field = V4L2_FIELD_NONE; | ||
2087 | v4l2_buffer.memory = V4L2_MEMORY_MMAP; | ||
2088 | v4l2_buffer.m.offset = index * FRAME_BUFFER_SIZE; | ||
2089 | v4l2_buffer.length = FRAME_BUFFER_SIZE; | ||
2090 | |||
2091 | JOM(16, " %10i=index\n", v4l2_buffer.index); | ||
2092 | JOM(16, " 0x%08X=type\n", v4l2_buffer.type); | ||
2093 | JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); | ||
2094 | JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); | ||
2095 | JOM(16, " %10i=field\n", v4l2_buffer.field); | ||
2096 | JOM(16, " %10li=timestamp.tv_usec\n", | ||
2097 | (long)v4l2_buffer.timestamp.tv_usec); | ||
2098 | JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); | ||
2099 | JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory); | ||
2100 | JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset); | ||
2101 | JOM(16, " %10i=length\n", v4l2_buffer.length); | ||
2102 | |||
2103 | if (copy_to_user((void __user *)arg, &v4l2_buffer, | ||
2104 | sizeof(struct v4l2_buffer))) { | ||
2105 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2106 | return -EFAULT; | ||
2107 | } | ||
2108 | break; | ||
2109 | } | ||
2110 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2111 | case VIDIOC_QBUF: { | ||
2112 | struct v4l2_buffer v4l2_buffer; | ||
2113 | |||
2114 | JOM(8, "VIDIOC_QBUF\n"); | ||
2115 | |||
2116 | if (0 != copy_from_user(&v4l2_buffer, (void __user *)arg, | ||
2117 | sizeof(struct v4l2_buffer))) { | ||
2118 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2119 | return -EFAULT; | ||
2120 | } | ||
2121 | |||
2122 | if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
2123 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2124 | return -EINVAL; | ||
2125 | } | ||
2126 | if (v4l2_buffer.memory != V4L2_MEMORY_MMAP) { | ||
2127 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2128 | return -EINVAL; | ||
2129 | } | ||
2130 | if (v4l2_buffer.index < 0 || | ||
2131 | v4l2_buffer.index >= peasycap->frame_buffer_many) { | ||
2132 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2133 | return -EINVAL; | ||
2134 | } | ||
2135 | v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED; | ||
2136 | |||
2137 | peasycap->done[v4l2_buffer.index] = 0; | ||
2138 | peasycap->queued[v4l2_buffer.index] = V4L2_BUF_FLAG_QUEUED; | ||
2139 | |||
2140 | if (copy_to_user((void __user *)arg, &v4l2_buffer, | ||
2141 | sizeof(struct v4l2_buffer))) { | ||
2142 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2143 | return -EFAULT; | ||
2144 | } | ||
2145 | |||
2146 | JOM(8, "..... user queueing frame buffer %i\n", | ||
2147 | (int)v4l2_buffer.index); | ||
2148 | |||
2149 | peasycap->frame_lock = 0; | ||
2150 | |||
2151 | break; | ||
2152 | } | ||
2153 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2154 | case VIDIOC_DQBUF: | ||
2155 | { | ||
2156 | struct timeval timeval, timeval2; | ||
2157 | int i, j; | ||
2158 | struct v4l2_buffer v4l2_buffer; | ||
2159 | int rcdq; | ||
2160 | u16 input; | ||
2161 | |||
2162 | JOM(8, "VIDIOC_DQBUF\n"); | ||
2163 | |||
2164 | if ((peasycap->video_idle) || (peasycap->video_eof)) { | ||
2165 | JOM(8, "returning -EIO because " | ||
2166 | "%i=video_idle %i=video_eof\n", | ||
2167 | peasycap->video_idle, peasycap->video_eof); | ||
2168 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2169 | return -EIO; | ||
2170 | } | ||
2171 | |||
2172 | if (copy_from_user(&v4l2_buffer, (void __user *)arg, | ||
2173 | sizeof(struct v4l2_buffer))) { | ||
2174 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2175 | return -EFAULT; | ||
2176 | } | ||
2177 | |||
2178 | if (v4l2_buffer.type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
2179 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2180 | return -EINVAL; | ||
2181 | } | ||
2182 | |||
2183 | if (peasycap->offerfields) { | ||
2184 | /*---------------------------------------------------*/ | ||
2185 | /* | ||
2186 | * IN ITS 50 "fps" MODE tvtime SEEMS ALWAYS TO REQUEST | ||
2187 | * V4L2_FIELD_BOTTOM | ||
2188 | */ | ||
2189 | /*---------------------------------------------------*/ | ||
2190 | if (V4L2_FIELD_TOP == v4l2_buffer.field) | ||
2191 | JOM(8, "user wants V4L2_FIELD_TOP\n"); | ||
2192 | else if (V4L2_FIELD_BOTTOM == v4l2_buffer.field) | ||
2193 | JOM(8, "user wants V4L2_FIELD_BOTTOM\n"); | ||
2194 | else if (V4L2_FIELD_ANY == v4l2_buffer.field) | ||
2195 | JOM(8, "user wants V4L2_FIELD_ANY\n"); | ||
2196 | else | ||
2197 | JOM(8, "user wants V4L2_FIELD_...UNKNOWN: %i\n", | ||
2198 | v4l2_buffer.field); | ||
2199 | } | ||
2200 | |||
2201 | if (!peasycap->video_isoc_streaming) { | ||
2202 | JOM(16, "returning -EIO because video urbs not streaming\n"); | ||
2203 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2204 | return -EIO; | ||
2205 | } | ||
2206 | /*-------------------------------------------------------------------*/ | ||
2207 | /* | ||
2208 | * IF THE USER HAS PREVIOUSLY CALLED easycap_poll(), | ||
2209 | * AS DETERMINED BY FINDING | ||
2210 | * THE FLAG peasycap->polled SET, THERE MUST BE | ||
2211 | * NO FURTHER WAIT HERE. IN THIS | ||
2212 | * CASE, JUST CHOOSE THE FRAME INDICATED BY peasycap->frame_read | ||
2213 | */ | ||
2214 | /*-------------------------------------------------------------------*/ | ||
2215 | |||
2216 | if (!peasycap->polled) { | ||
2217 | do { | ||
2218 | rcdq = easycap_dqbuf(peasycap, 0); | ||
2219 | if (-EIO == rcdq) { | ||
2220 | JOM(8, "returning -EIO because " | ||
2221 | "dqbuf() returned -EIO\n"); | ||
2222 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2223 | return -EIO; | ||
2224 | } | ||
2225 | } while (0 != rcdq); | ||
2226 | } else { | ||
2227 | if (peasycap->video_eof) { | ||
2228 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2229 | return -EIO; | ||
2230 | } | ||
2231 | } | ||
2232 | if (V4L2_BUF_FLAG_DONE != peasycap->done[peasycap->frame_read]) { | ||
2233 | JOM(8, "V4L2_BUF_FLAG_DONE != 0x%08X\n", | ||
2234 | peasycap->done[peasycap->frame_read]); | ||
2235 | } | ||
2236 | peasycap->polled = 0; | ||
2237 | |||
2238 | if (!(peasycap->isequence % 10)) { | ||
2239 | for (i = 0; i < 179; i++) | ||
2240 | peasycap->merit[i] = peasycap->merit[i+1]; | ||
2241 | peasycap->merit[179] = merit_saa(peasycap->pusb_device); | ||
2242 | j = 0; | ||
2243 | for (i = 0; i < 180; i++) | ||
2244 | j += peasycap->merit[i]; | ||
2245 | if (90 < j) { | ||
2246 | SAM("easycap driver shutting down " | ||
2247 | "on condition blue\n"); | ||
2248 | peasycap->video_eof = 1; | ||
2249 | peasycap->audio_eof = 1; | ||
2250 | } | ||
2251 | } | ||
2252 | |||
2253 | v4l2_buffer.index = peasycap->frame_read; | ||
2254 | v4l2_buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
2255 | v4l2_buffer.bytesused = peasycap->frame_buffer_used; | ||
2256 | v4l2_buffer.flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; | ||
2257 | if (peasycap->offerfields) | ||
2258 | v4l2_buffer.field = V4L2_FIELD_BOTTOM; | ||
2259 | else | ||
2260 | v4l2_buffer.field = V4L2_FIELD_NONE; | ||
2261 | do_gettimeofday(&timeval); | ||
2262 | timeval2 = timeval; | ||
2263 | |||
2264 | v4l2_buffer.timestamp = timeval2; | ||
2265 | v4l2_buffer.sequence = peasycap->isequence++; | ||
2266 | v4l2_buffer.memory = V4L2_MEMORY_MMAP; | ||
2267 | v4l2_buffer.m.offset = v4l2_buffer.index * FRAME_BUFFER_SIZE; | ||
2268 | v4l2_buffer.length = FRAME_BUFFER_SIZE; | ||
2269 | |||
2270 | JOM(16, " %10i=index\n", v4l2_buffer.index); | ||
2271 | JOM(16, " 0x%08X=type\n", v4l2_buffer.type); | ||
2272 | JOM(16, " %10i=bytesused\n", v4l2_buffer.bytesused); | ||
2273 | JOM(16, " 0x%08X=flags\n", v4l2_buffer.flags); | ||
2274 | JOM(16, " %10i=field\n", v4l2_buffer.field); | ||
2275 | JOM(16, " %10li=timestamp.tv_sec\n", | ||
2276 | (long)v4l2_buffer.timestamp.tv_sec); | ||
2277 | JOM(16, " %10li=timestamp.tv_usec\n", | ||
2278 | (long)v4l2_buffer.timestamp.tv_usec); | ||
2279 | JOM(16, " %10i=sequence\n", v4l2_buffer.sequence); | ||
2280 | JOM(16, " 0x%08X=memory\n", v4l2_buffer.memory); | ||
2281 | JOM(16, " %10i=m.offset\n", v4l2_buffer.m.offset); | ||
2282 | JOM(16, " %10i=length\n", v4l2_buffer.length); | ||
2283 | |||
2284 | if (copy_to_user((void __user *)arg, &v4l2_buffer, | ||
2285 | sizeof(struct v4l2_buffer))) { | ||
2286 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2287 | return -EFAULT; | ||
2288 | } | ||
2289 | |||
2290 | input = peasycap->frame_buffer[peasycap->frame_read][0].input; | ||
2291 | if (0x08 & input) { | ||
2292 | JOM(8, "user is offered frame buffer %i, input %i\n", | ||
2293 | peasycap->frame_read, (0x07 & input)); | ||
2294 | } else { | ||
2295 | JOM(8, "user is offered frame buffer %i\n", | ||
2296 | peasycap->frame_read); | ||
2297 | } | ||
2298 | peasycap->frame_lock = 1; | ||
2299 | JOM(8, "%i=peasycap->frame_fill\n", peasycap->frame_fill); | ||
2300 | if (peasycap->frame_read == peasycap->frame_fill) { | ||
2301 | if (peasycap->frame_lock) { | ||
2302 | JOM(8, "WORRY: filling frame buffer " | ||
2303 | "while offered to user\n"); | ||
2304 | } | ||
2305 | } | ||
2306 | break; | ||
2307 | } | ||
2308 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2309 | case VIDIOC_STREAMON: { | ||
2310 | int i; | ||
2311 | |||
2312 | JOM(8, "VIDIOC_STREAMON\n"); | ||
2313 | |||
2314 | peasycap->isequence = 0; | ||
2315 | for (i = 0; i < 180; i++) | ||
2316 | peasycap->merit[i] = 0; | ||
2317 | if (!peasycap->pusb_device) { | ||
2318 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
2319 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2320 | return -EFAULT; | ||
2321 | } | ||
2322 | submit_video_urbs(peasycap); | ||
2323 | peasycap->video_idle = 0; | ||
2324 | peasycap->audio_idle = 0; | ||
2325 | peasycap->video_eof = 0; | ||
2326 | peasycap->audio_eof = 0; | ||
2327 | break; | ||
2328 | } | ||
2329 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2330 | case VIDIOC_STREAMOFF: { | ||
2331 | JOM(8, "VIDIOC_STREAMOFF\n"); | ||
2332 | |||
2333 | if (!peasycap->pusb_device) { | ||
2334 | SAM("ERROR: peasycap->pusb_device is NULL\n"); | ||
2335 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2336 | return -EFAULT; | ||
2337 | } | ||
2338 | |||
2339 | peasycap->video_idle = 1; | ||
2340 | peasycap->audio_idle = 1; | ||
2341 | peasycap->timeval0.tv_sec = 0; | ||
2342 | /*---------------------------------------------------------------------------*/ | ||
2343 | /* | ||
2344 | * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO THE STREAMOFF COMMAND | ||
2345 | * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE. | ||
2346 | */ | ||
2347 | /*---------------------------------------------------------------------------*/ | ||
2348 | JOM(8, "calling wake_up on wq_video and wq_audio\n"); | ||
2349 | wake_up_interruptible(&(peasycap->wq_video)); | ||
2350 | if (peasycap->psubstream) | ||
2351 | snd_pcm_period_elapsed(peasycap->psubstream); | ||
2352 | break; | ||
2353 | } | ||
2354 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2355 | case VIDIOC_G_PARM: { | ||
2356 | struct v4l2_streamparm *pv4l2_streamparm; | ||
2357 | |||
2358 | JOM(8, "VIDIOC_G_PARM\n"); | ||
2359 | pv4l2_streamparm = kzalloc(sizeof(struct v4l2_streamparm), GFP_KERNEL); | ||
2360 | if (!pv4l2_streamparm) { | ||
2361 | SAM("ERROR: out of memory\n"); | ||
2362 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2363 | return -ENOMEM; | ||
2364 | } | ||
2365 | if (copy_from_user(pv4l2_streamparm, | ||
2366 | (void __user *)arg, sizeof(struct v4l2_streamparm))) { | ||
2367 | kfree(pv4l2_streamparm); | ||
2368 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2369 | return -EFAULT; | ||
2370 | } | ||
2371 | |||
2372 | if (pv4l2_streamparm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
2373 | kfree(pv4l2_streamparm); | ||
2374 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2375 | return -EINVAL; | ||
2376 | } | ||
2377 | pv4l2_streamparm->parm.capture.capability = 0; | ||
2378 | pv4l2_streamparm->parm.capture.capturemode = 0; | ||
2379 | pv4l2_streamparm->parm.capture.timeperframe.numerator = 1; | ||
2380 | |||
2381 | if (peasycap->fps) { | ||
2382 | pv4l2_streamparm->parm.capture.timeperframe. | ||
2383 | denominator = peasycap->fps; | ||
2384 | } else { | ||
2385 | if (peasycap->ntsc) { | ||
2386 | pv4l2_streamparm->parm.capture.timeperframe. | ||
2387 | denominator = 30; | ||
2388 | } else { | ||
2389 | pv4l2_streamparm->parm.capture.timeperframe. | ||
2390 | denominator = 25; | ||
2391 | } | ||
2392 | } | ||
2393 | |||
2394 | pv4l2_streamparm->parm.capture.readbuffers = | ||
2395 | peasycap->frame_buffer_many; | ||
2396 | pv4l2_streamparm->parm.capture.extendedmode = 0; | ||
2397 | if (copy_to_user((void __user *)arg, | ||
2398 | pv4l2_streamparm, | ||
2399 | sizeof(struct v4l2_streamparm))) { | ||
2400 | kfree(pv4l2_streamparm); | ||
2401 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2402 | return -EFAULT; | ||
2403 | } | ||
2404 | kfree(pv4l2_streamparm); | ||
2405 | break; | ||
2406 | } | ||
2407 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2408 | case VIDIOC_S_PARM: { | ||
2409 | JOM(8, "VIDIOC_S_PARM unsupported\n"); | ||
2410 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2411 | return -EINVAL; | ||
2412 | } | ||
2413 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2414 | case VIDIOC_G_AUDIO: { | ||
2415 | JOM(8, "VIDIOC_G_AUDIO unsupported\n"); | ||
2416 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2417 | return -EINVAL; | ||
2418 | } | ||
2419 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2420 | case VIDIOC_S_AUDIO: { | ||
2421 | JOM(8, "VIDIOC_S_AUDIO unsupported\n"); | ||
2422 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2423 | return -EINVAL; | ||
2424 | } | ||
2425 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2426 | case VIDIOC_S_TUNER: { | ||
2427 | JOM(8, "VIDIOC_S_TUNER unsupported\n"); | ||
2428 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2429 | return -EINVAL; | ||
2430 | } | ||
2431 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2432 | case VIDIOC_G_FBUF: | ||
2433 | case VIDIOC_S_FBUF: | ||
2434 | case VIDIOC_OVERLAY: { | ||
2435 | JOM(8, "VIDIOC_G_FBUF|VIDIOC_S_FBUF|VIDIOC_OVERLAY unsupported\n"); | ||
2436 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2437 | return -EINVAL; | ||
2438 | } | ||
2439 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2440 | case VIDIOC_G_TUNER: { | ||
2441 | JOM(8, "VIDIOC_G_TUNER unsupported\n"); | ||
2442 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2443 | return -EINVAL; | ||
2444 | } | ||
2445 | case VIDIOC_G_FREQUENCY: | ||
2446 | case VIDIOC_S_FREQUENCY: { | ||
2447 | JOM(8, "VIDIOC_G_FREQUENCY|VIDIOC_S_FREQUENCY unsupported\n"); | ||
2448 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2449 | return -EINVAL; | ||
2450 | } | ||
2451 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
2452 | default: { | ||
2453 | JOM(8, "ERROR: unrecognized V4L2 IOCTL command: 0x%08X\n", cmd); | ||
2454 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2455 | return -ENOIOCTLCMD; | ||
2456 | } | ||
2457 | } | ||
2458 | mutex_unlock(&easycapdc60_dongle[kd].mutex_video); | ||
2459 | JOM(4, "unlocked easycapdc60_dongle[%i].mutex_video\n", kd); | ||
2460 | return 0; | ||
2461 | } | ||
2462 | /*****************************************************************************/ | ||