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