easycap: fix ntsc module parameter description
[deliverable/linux.git] / drivers / staging / easycap / easycap_main.c
CommitLineData
702422bd
T
1/******************************************************************************
2* *
3* easycap_main.c *
4* *
5* Video driver for EasyCAP USB2.0 Video Capture Device DC60 *
6* *
7* *
8******************************************************************************/
9/*
10 *
11 * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
12 *
13 *
14 * This is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * The software is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this software; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 *
28*/
29/*****************************************************************************/
30
31#include "easycap.h"
fc3cc2ca 32#include <linux/usb/audio.h>
702422bd 33
02149cf7
TW
34
35MODULE_LICENSE("GPL");
36MODULE_AUTHOR("R.M. Thomas <rmthomas@sciolus.org>");
37MODULE_DESCRIPTION(EASYCAP_DRIVER_DESCRIPTION);
38MODULE_VERSION(EASYCAP_DRIVER_VERSION);
39
40#ifdef CONFIG_EASYCAP_DEBUG
18545cfd 41int easycap_debug;
62af33ec 42module_param_named(debug, easycap_debug, int, S_IRUGO | S_IWUSR);
02149cf7
TW
43MODULE_PARM_DESC(debug, "Debug level: 0(default),1,2,...,9");
44#endif /* CONFIG_EASYCAP_DEBUG */
45
2ef0c05e
TW
46bool easycap_readback;
47module_param_named(readback, easycap_readback, bool, S_IRUGO | S_IWUSR);
48MODULE_PARM_DESC(readback, "read back written registers: (default false)");
49
02149cf7 50static int easycap_bars = 1;
62af33ec 51module_param_named(bars, easycap_bars, int, S_IRUGO | S_IWUSR);
02149cf7
TW
52MODULE_PARM_DESC(bars,
53 "Testcard bars on input signal failure: 0=>no, 1=>yes(default)");
702422bd 54
02149cf7
TW
55static int easycap_gain = 16;
56module_param_named(gain, easycap_gain, int, S_IRUGO | S_IWUSR);
57MODULE_PARM_DESC(gain, "Audio gain: 0,...,16(default),...31");
d090bf57 58
8d613954
TW
59static bool easycap_ntsc;
60module_param_named(ntsc, easycap_ntsc, bool, S_IRUGO | S_IWUSR);
aa3e842d 61MODULE_PARM_DESC(ntsc, "NTSC default encoding (default PAL)");
8d613954 62
d090bf57
TW
63
64
a9855917
MT
65struct easycap_dongle easycapdc60_dongle[DONGLE_MANY];
66static struct mutex mutex_dongle;
d090bf57
TW
67static void easycap_complete(struct urb *purb);
68static int reset(struct easycap *peasycap);
e68703cf 69
5c0c6c39
TW
70const char *strerror(int err)
71{
72#define ERRNOSTR(_e) case _e: return # _e
73 switch (err) {
74 case 0: return "OK";
75 ERRNOSTR(ENOMEM);
76 ERRNOSTR(ENODEV);
77 ERRNOSTR(ENXIO);
78 ERRNOSTR(EINVAL);
79 ERRNOSTR(EAGAIN);
80 ERRNOSTR(EFBIG);
81 ERRNOSTR(EPIPE);
82 ERRNOSTR(EMSGSIZE);
83 ERRNOSTR(ENOSPC);
84 ERRNOSTR(EINPROGRESS);
85 ERRNOSTR(ENOSR);
86 ERRNOSTR(EOVERFLOW);
87 ERRNOSTR(EPROTO);
88 ERRNOSTR(EILSEQ);
89 ERRNOSTR(ETIMEDOUT);
90 ERRNOSTR(EOPNOTSUPP);
91 ERRNOSTR(EPFNOSUPPORT);
92 ERRNOSTR(EAFNOSUPPORT);
93 ERRNOSTR(EADDRINUSE);
94 ERRNOSTR(EADDRNOTAVAIL);
95 ERRNOSTR(ENOBUFS);
96 ERRNOSTR(EISCONN);
97 ERRNOSTR(ENOTCONN);
98 ERRNOSTR(ESHUTDOWN);
99 ERRNOSTR(ENOENT);
100 ERRNOSTR(ECONNRESET);
101 ERRNOSTR(ETIME);
102 ERRNOSTR(ECOMM);
103 ERRNOSTR(EREMOTEIO);
104 ERRNOSTR(EXDEV);
105 ERRNOSTR(EPERM);
106 default: return "unknown";
107 }
108
109#undef ERRNOSTR
110}
111
702422bd
T
112/*---------------------------------------------------------------------------*/
113/*
114 * PARAMETERS USED WHEN REGISTERING THE VIDEO INTERFACE
115 *
116 * NOTE: SOME KERNELS IGNORE usb_class_driver.minor_base, AS MENTIONED BY
117 * CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGE 253.
118 * THIS IS THE CASE FOR OpenSUSE.
119 */
120/*---------------------------------------------------------------------------*/
702422bd 121/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
702422bd 122/****************************************************************************/
e68703cf 123/*---------------------------------------------------------------------------*/
702422bd 124/*
268dfede 125 * THIS ROUTINE DOES NOT DETECT DUPLICATE OCCURRENCES OF POINTER peasycap
e68703cf
MT
126*/
127/*---------------------------------------------------------------------------*/
c7506658 128int isdongle(struct easycap *peasycap)
e68703cf 129{
c7506658 130 int k;
6888393c 131 if (!peasycap)
c7506658
TW
132 return -2;
133 for (k = 0; k < DONGLE_MANY; k++) {
134 if (easycapdc60_dongle[k].peasycap == peasycap) {
135 peasycap->isdongle = k;
136 return k;
137 }
e68703cf 138 }
c7506658 139 return -1;
e68703cf 140}
702422bd 141/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
d090bf57 142static int easycap_open(struct inode *inode, struct file *file)
702422bd 143{
c7506658 144 struct video_device *pvideo_device;
c7506658
TW
145 struct easycap *peasycap;
146 int rc;
702422bd 147
c7506658
TW
148 JOT(4, "\n");
149 SAY("==========OPEN=========\n");
702422bd 150
c7506658 151 pvideo_device = video_devdata(file);
6888393c 152 if (!pvideo_device) {
c7506658
TW
153 SAY("ERROR: pvideo_device is NULL.\n");
154 return -EFAULT;
155 }
156 peasycap = (struct easycap *)video_get_drvdata(pvideo_device);
6888393c 157 if (!peasycap) {
c7506658
TW
158 SAY("ERROR: peasycap is NULL\n");
159 return -EFAULT;
160 }
6888393c 161 if (!peasycap->pusb_device) {
c7506658
TW
162 SAM("ERROR: peasycap->pusb_device is NULL\n");
163 return -EFAULT;
164 } else {
165 JOM(16, "peasycap->pusb_device=%p\n", peasycap->pusb_device);
166 }
167 file->private_data = peasycap;
168 rc = wakeup_device(peasycap->pusb_device);
169 if (0 == rc)
170 JOM(8, "wakeup_device() OK\n");
171 else {
172 SAM("ERROR: wakeup_device() rc = %i\n", rc);
173 if (-ENODEV == rc)
174 SAM("ERROR: wakeup_device() returned -ENODEV\n");
175 else
176 SAM("ERROR: wakeup_device() rc = %i\n", rc);
177 return rc;
178 }
179 peasycap->input = 0;
180 rc = reset(peasycap);
181 if (rc) {
182 SAM("ERROR: reset() rc = %i\n", rc);
183 return -EFAULT;
184 }
185 return 0;
f36bc37a 186}
d090bf57 187
f36bc37a
MT
188/*****************************************************************************/
189/*---------------------------------------------------------------------------*/
190/*
191 * RESET THE HARDWARE TO ITS REFERENCE STATE.
192 *
193 * THIS ROUTINE MAY BE CALLED REPEATEDLY IF easycap_complete() DETECTS
194 * A BAD VIDEO FRAME SIZE.
195*/
196/*---------------------------------------------------------------------------*/
d090bf57 197static int reset(struct easycap *peasycap)
f36bc37a 198{
c7506658 199 struct easycap_standard const *peasycap_standard;
fd1b821c 200 int fmtidx, input, rate;
c7506658 201 bool ntsc, other;
fd1b821c 202 int rc;
f36bc37a 203
6888393c 204 if (!peasycap) {
c7506658
TW
205 SAY("ERROR: peasycap is NULL\n");
206 return -EFAULT;
207 }
208 input = peasycap->input;
f36bc37a
MT
209
210/*---------------------------------------------------------------------------*/
211/*
ae59dad4 212 * IF THE SAA7113H HAS ALREADY ACQUIRED SYNC, USE ITS HARDWARE-DETECTED
f36bc37a
MT
213 * FIELD FREQUENCY TO DISTINGUISH NTSC FROM PAL. THIS IS ESSENTIAL FOR
214 * gstreamer AND OTHER USERSPACE PROGRAMS WHICH MAY NOT ATTEMPT TO INITIATE
215 * A SWITCH BETWEEN PAL AND NTSC.
216 *
217 * FUNCTION ready_saa() MAY REQUIRE A SUBSTANTIAL FRACTION OF A SECOND TO
218 * COMPLETE, SO SHOULD NOT BE INVOKED WITHOUT GOOD REASON.
219*/
220/*---------------------------------------------------------------------------*/
c7506658
TW
221 other = false;
222 JOM(8, "peasycap->ntsc=%d\n", peasycap->ntsc);
223
224 rate = ready_saa(peasycap->pusb_device);
fd1b821c 225 if (rate < 0) {
c7506658 226 JOM(8, "not ready to capture after %i ms ...\n", PATIENCE);
fd1b821c
TW
227 ntsc = !peasycap->ntsc;
228 JOM(8, "... trying %s ..\n", ntsc ? "NTSC" : "PAL");
229 rc = setup_stk(peasycap->pusb_device, ntsc);
230 if (rc) {
231 SAM("ERROR: setup_stk() rc = %i\n", rc);
232 return -EFAULT;
233 }
234 rc = setup_saa(peasycap->pusb_device, ntsc);
235 if (rc) {
236 SAM("ERROR: setup_saa() rc = %i\n", rc);
237 return -EFAULT;
238 }
239
240 rate = ready_saa(peasycap->pusb_device);
241 if (rate < 0) {
242 JOM(8, "not ready to capture after %i ms\n", PATIENCE);
243 JOM(8, "... saa register 0x1F has 0x%02X\n",
c7506658 244 read_saa(peasycap->pusb_device, 0x1F));
fd1b821c 245 ntsc = peasycap->ntsc;
c7506658
TW
246 } else {
247 JOM(8, "... success at second try: %i=rate\n", rate);
248 ntsc = (0 < (rate/2)) ? true : false ;
249 other = true;
250 }
f36bc37a 251 } else {
c7506658
TW
252 JOM(8, "... success at first try: %i=rate\n", rate);
253 ntsc = (0 < rate/2) ? true : false ;
254 }
255 JOM(8, "ntsc=%d\n", ntsc);
256/*---------------------------------------------------------------------------*/
257
258 rc = setup_stk(peasycap->pusb_device, ntsc);
fd1b821c 259 if (rc) {
c7506658
TW
260 SAM("ERROR: setup_stk() rc = %i\n", rc);
261 return -EFAULT;
262 }
263 rc = setup_saa(peasycap->pusb_device, ntsc);
fd1b821c 264 if (rc) {
c7506658
TW
265 SAM("ERROR: setup_saa() rc = %i\n", rc);
266 return -EFAULT;
f36bc37a 267 }
702422bd 268
fd1b821c 269 memset(peasycap->merit, 0, sizeof(peasycap->merit));
c7506658
TW
270
271 peasycap->video_eof = 0;
272 peasycap->audio_eof = 0;
273 do_gettimeofday(&peasycap->timeval7);
f36bc37a
MT
274/*---------------------------------------------------------------------------*/
275/*
276 * RESTORE INPUT AND FORCE REFRESH OF STANDARD, FORMAT, ETC.
277 *
278 * WHILE THIS PROCEDURE IS IN PROGRESS, SOME IOCTL COMMANDS WILL RETURN -EBUSY.
279*/
280/*---------------------------------------------------------------------------*/
c7506658
TW
281 peasycap->input = -8192;
282 peasycap->standard_offset = -8192;
283 fmtidx = ntsc ? NTSC_M : PAL_BGHIN;
284 if (other) {
285 peasycap_standard = &easycap_standard[0];
286 while (0xFFFF != peasycap_standard->mask) {
287 if (fmtidx == peasycap_standard->v4l2_standard.index) {
1dc6e418 288 peasycap->inputset[input].standard_offset =
c7506658 289 peasycap_standard - easycap_standard;
f36bc37a
MT
290 break;
291 }
c7506658 292 peasycap_standard++;
f36bc37a 293 }
c7506658
TW
294 if (0xFFFF == peasycap_standard->mask) {
295 SAM("ERROR: standard not found\n");
296 return -EINVAL;
297 }
298 JOM(8, "%i=peasycap->inputset[%i].standard_offset\n",
299 peasycap->inputset[input].standard_offset, input);
f36bc37a 300 }
c7506658
TW
301 peasycap->format_offset = -8192;
302 peasycap->brightness = -8192;
303 peasycap->contrast = -8192;
304 peasycap->saturation = -8192;
305 peasycap->hue = -8192;
f36bc37a 306
c7506658 307 rc = newinput(peasycap, input);
702422bd 308
c7506658
TW
309 if (rc) {
310 SAM("ERROR: newinput(.,%i) rc = %i\n", rc, input);
311 return -EFAULT;
312 }
f36bc37a 313 JOM(4, "restored input, standard and format\n");
c7506658
TW
314
315 JOM(8, "true=peasycap->ntsc %d\n", peasycap->ntsc);
316
317 if (0 > peasycap->input) {
318 SAM("MISTAKE: %i=peasycap->input\n", peasycap->input);
319 return -ENOENT;
320 }
321 if (0 > peasycap->standard_offset) {
322 SAM("MISTAKE: %i=peasycap->standard_offset\n",
323 peasycap->standard_offset);
324 return -ENOENT;
325 }
326 if (0 > peasycap->format_offset) {
327 SAM("MISTAKE: %i=peasycap->format_offset\n",
328 peasycap->format_offset);
329 return -ENOENT;
330 }
331 if (0 > peasycap->brightness) {
332 SAM("MISTAKE: %i=peasycap->brightness\n",
333 peasycap->brightness);
334 return -ENOENT;
335 }
336 if (0 > peasycap->contrast) {
337 SAM("MISTAKE: %i=peasycap->contrast\n", peasycap->contrast);
338 return -ENOENT;
339 }
340 if (0 > peasycap->saturation) {
341 SAM("MISTAKE: %i=peasycap->saturation\n",
342 peasycap->saturation);
343 return -ENOENT;
344 }
345 if (0 > peasycap->hue) {
346 SAM("MISTAKE: %i=peasycap->hue\n", peasycap->hue);
347 return -ENOENT;
348 }
349 return 0;
f36bc37a
MT
350}
351/*****************************************************************************/
352/*---------------------------------------------------------------------------*/
353/*
354 * IF THE REQUESTED INPUT IS THE SAME AS THE EXISTING INPUT, DO NOTHING.
355 * OTHERWISE:
356 * KILL URBS, CLEAR FIELD AND FRAME BUFFERS AND RESET THEIR
357 * _read AND _fill POINTERS.
358 * SELECT THE NEW INPUT.
359 * ADJUST THE STANDARD, FORMAT, BRIGHTNESS, CONTRAST, SATURATION AND HUE
360 * ON THE BASIS OF INFORMATION IN STRUCTURE easycap.inputset[input].
361 * RESUBMIT THE URBS IF STREAMING WAS ALREADY IN PROGRESS.
362 *
363 * NOTE:
364 * THIS ROUTINE MAY BE CALLED FREQUENTLY BY ZONEMINDER VIA IOCTL,
365 * SO IT SHOULD WRITE ONLY SPARINGLY TO THE LOGFILE.
366*/
367/*---------------------------------------------------------------------------*/
368int
369newinput(struct easycap *peasycap, int input)
370{
c7506658
TW
371 int rc, k, m, mood, off;
372 int inputnow, video_idlenow, audio_idlenow;
373 bool resubmit;
f36bc37a 374
6888393c 375 if (!peasycap) {
c7506658
TW
376 SAY("ERROR: peasycap is NULL\n");
377 return -EFAULT;
378 }
379 JOM(8, "%i=input sought\n", input);
702422bd 380
c7506658
TW
381 if (0 > input && INPUT_MANY <= input)
382 return -ENOENT;
383 inputnow = peasycap->input;
384 if (input == inputnow)
385 return 0;
702422bd 386/*---------------------------------------------------------------------------*/
f36bc37a
MT
387/*
388 * IF STREAMING IS IN PROGRESS THE URBS ARE KILLED AT THIS
389 * STAGE AND WILL BE RESUBMITTED PRIOR TO EXIT FROM THE ROUTINE.
390 * IF NO STREAMING IS IN PROGRESS NO URBS WILL BE SUBMITTED BY THE
391 * ROUTINE.
392*/
393/*---------------------------------------------------------------------------*/
c7506658
TW
394 video_idlenow = peasycap->video_idle;
395 audio_idlenow = peasycap->audio_idle;
f36bc37a 396
c7506658
TW
397 peasycap->video_idle = 1;
398 peasycap->audio_idle = 1;
399 if (peasycap->video_isoc_streaming) {
400 resubmit = true;
401 kill_video_urbs(peasycap);
402 } else {
403 resubmit = false;
404 }
f36bc37a 405/*---------------------------------------------------------------------------*/
6888393c 406 if (!peasycap->pusb_device) {
c7506658
TW
407 SAM("ERROR: peasycap->pusb_device is NULL\n");
408 return -ENODEV;
409 }
410 rc = usb_set_interface(peasycap->pusb_device,
411 peasycap->video_interface,
412 peasycap->video_altsetting_off);
413 if (rc) {
414 SAM("ERROR: usb_set_interface() rc = %i\n", rc);
415 return -EFAULT;
416 }
417 rc = stop_100(peasycap->pusb_device);
418 if (rc) {
419 SAM("ERROR: stop_100() rc = %i\n", rc);
420 return -EFAULT;
421 }
422 for (k = 0; k < FIELD_BUFFER_MANY; k++) {
423 for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++)
424 memset(peasycap->field_buffer[k][m].pgo, 0, PAGE_SIZE);
425 }
426 for (k = 0; k < FRAME_BUFFER_MANY; k++) {
427 for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++)
428 memset(peasycap->frame_buffer[k][m].pgo, 0, PAGE_SIZE);
429 }
430 peasycap->field_page = 0;
431 peasycap->field_read = 0;
432 peasycap->field_fill = 0;
433
434 peasycap->frame_read = 0;
435 peasycap->frame_fill = 0;
436 for (k = 0; k < peasycap->input; k++) {
437 (peasycap->frame_fill)++;
438 if (peasycap->frame_buffer_many <= peasycap->frame_fill)
439 peasycap->frame_fill = 0;
440 }
441 peasycap->input = input;
442 select_input(peasycap->pusb_device, peasycap->input, 9);
f36bc37a 443/*---------------------------------------------------------------------------*/
c7506658
TW
444 if (input == peasycap->inputset[input].input) {
445 off = peasycap->inputset[input].standard_offset;
446 if (off != peasycap->standard_offset) {
447 rc = adjust_standard(peasycap,
f36bc37a 448 easycap_standard[off].v4l2_standard.id);
c7506658
TW
449 if (rc) {
450 SAM("ERROR: adjust_standard() rc = %i\n", rc);
451 return -EFAULT;
452 }
453 JOM(8, "%i=peasycap->standard_offset\n",
454 peasycap->standard_offset);
455 } else {
456 JOM(8, "%i=peasycap->standard_offset unchanged\n",
f36bc37a 457 peasycap->standard_offset);
f36bc37a 458 }
c7506658
TW
459 off = peasycap->inputset[input].format_offset;
460 if (off != peasycap->format_offset) {
461 struct v4l2_pix_format *pix =
462 &easycap_format[off].v4l2_format.fmt.pix;
463 rc = adjust_format(peasycap,
464 pix->width, pix->height,
465 pix->pixelformat, pix->field, false);
466 if (0 > rc) {
467 SAM("ERROR: adjust_format() rc = %i\n", rc);
468 return -EFAULT;
469 }
470 JOM(8, "%i=peasycap->format_offset\n",
471 peasycap->format_offset);
472 } else {
473 JOM(8, "%i=peasycap->format_offset unchanged\n",
474 peasycap->format_offset);
f36bc37a 475 }
c7506658
TW
476 mood = peasycap->inputset[input].brightness;
477 if (mood != peasycap->brightness) {
478 rc = adjust_brightness(peasycap, mood);
479 if (rc) {
480 SAM("ERROR: adjust_brightness rc = %i\n", rc);
481 return -EFAULT;
482 }
483 JOM(8, "%i=peasycap->brightness\n",
484 peasycap->brightness);
f36bc37a 485 }
c7506658
TW
486 mood = peasycap->inputset[input].contrast;
487 if (mood != peasycap->contrast) {
488 rc = adjust_contrast(peasycap, mood);
489 if (rc) {
490 SAM("ERROR: adjust_contrast rc = %i\n", rc);
491 return -EFAULT;
492 }
493 JOM(8, "%i=peasycap->contrast\n", peasycap->contrast);
f36bc37a 494 }
c7506658
TW
495 mood = peasycap->inputset[input].saturation;
496 if (mood != peasycap->saturation) {
497 rc = adjust_saturation(peasycap, mood);
498 if (rc) {
499 SAM("ERROR: adjust_saturation rc = %i\n", rc);
500 return -EFAULT;
501 }
502 JOM(8, "%i=peasycap->saturation\n",
503 peasycap->saturation);
504 }
505 mood = peasycap->inputset[input].hue;
506 if (mood != peasycap->hue) {
507 rc = adjust_hue(peasycap, mood);
508 if (rc) {
509 SAM("ERROR: adjust_hue rc = %i\n", rc);
510 return -EFAULT;
511 }
512 JOM(8, "%i=peasycap->hue\n", peasycap->hue);
f36bc37a 513 }
c7506658
TW
514 } else {
515 SAM("MISTAKE: easycap.inputset[%i] unpopulated\n", input);
516 return -ENOENT;
f36bc37a 517 }
702422bd 518/*---------------------------------------------------------------------------*/
6888393c 519 if (!peasycap->pusb_device) {
c7506658
TW
520 SAM("ERROR: peasycap->pusb_device is NULL\n");
521 return -ENODEV;
522 }
523 rc = usb_set_interface(peasycap->pusb_device,
524 peasycap->video_interface,
525 peasycap->video_altsetting_on);
526 if (rc) {
527 SAM("ERROR: usb_set_interface() rc = %i\n", rc);
528 return -EFAULT;
529 }
530 rc = start_100(peasycap->pusb_device);
531 if (rc) {
532 SAM("ERROR: start_100() rc = %i\n", rc);
533 return -EFAULT;
534 }
27d683ab 535 if (resubmit)
c7506658 536 submit_video_urbs(peasycap);
f36bc37a 537
c7506658
TW
538 peasycap->video_isoc_sequence = VIDEO_ISOC_BUFFER_MANY - 1;
539 peasycap->video_idle = video_idlenow;
540 peasycap->audio_idle = audio_idlenow;
541 peasycap->video_junk = 0;
702422bd 542
c7506658 543 return 0;
702422bd
T
544}
545/*****************************************************************************/
d090bf57 546int submit_video_urbs(struct easycap *peasycap)
702422bd 547{
c7506658
TW
548 struct data_urb *pdata_urb;
549 struct urb *purb;
550 struct list_head *plist_head;
551 int j, isbad, nospc, m, rc;
552 int isbuf;
e68703cf 553
6888393c 554 if (!peasycap) {
c7506658
TW
555 SAY("ERROR: peasycap is NULL\n");
556 return -EFAULT;
557 }
558
6888393c 559 if (!peasycap->purb_video_head) {
c7506658
TW
560 SAY("ERROR: peasycap->urb_video_head uninitialized\n");
561 return -EFAULT;
562 }
6888393c 563 if (!peasycap->pusb_device) {
c7506658
TW
564 SAY("ERROR: peasycap->pusb_device is NULL\n");
565 return -ENODEV;
566 }
567 if (!peasycap->video_isoc_streaming) {
568 JOM(4, "submission of all video urbs\n");
569 isbad = 0; nospc = 0; m = 0;
570 list_for_each(plist_head, (peasycap->purb_video_head)) {
571 pdata_urb = list_entry(plist_head,
572 struct data_urb, list_head);
573 if (pdata_urb && pdata_urb->purb) {
574 purb = pdata_urb->purb;
702422bd
T
575 isbuf = pdata_urb->isbuf;
576 purb->interval = 1;
577 purb->dev = peasycap->pusb_device;
1dc6e418
TW
578 purb->pipe =
579 usb_rcvisocpipe(peasycap->pusb_device,
702422bd
T
580 peasycap->video_endpointnumber);
581 purb->transfer_flags = URB_ISO_ASAP;
1dc6e418 582 purb->transfer_buffer =
702422bd 583 peasycap->video_isoc_buffer[isbuf].pgo;
1dc6e418 584 purb->transfer_buffer_length =
702422bd
T
585 peasycap->video_isoc_buffer_size;
586 purb->complete = easycap_complete;
587 purb->context = peasycap;
588 purb->start_frame = 0;
1dc6e418 589 purb->number_of_packets =
702422bd
T
590 peasycap->video_isoc_framesperdesc;
591
c7506658
TW
592 for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
593 purb->iso_frame_desc[j]. offset =
594 j * peasycap->video_isoc_maxframesize;
595 purb->iso_frame_desc[j]. length =
596 peasycap->video_isoc_maxframesize;
597 }
702422bd
T
598
599 rc = usb_submit_urb(purb, GFP_KERNEL);
5c0c6c39 600 if (rc) {
702422bd 601 isbad++;
1dc6e418 602 SAM("ERROR: usb_submit_urb() failed "
c7506658 603 "for urb with rc:-%s\n",
5c0c6c39
TW
604 strerror(rc));
605 if (rc == -ENOSPC)
e68703cf 606 nospc++;
702422bd
T
607 } else {
608 m++;
609 }
702422bd 610 } else {
5c0c6c39 611 isbad++;
702422bd
T
612 }
613 }
c7506658
TW
614 if (nospc) {
615 SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
616 SAM("..... possibly inadequate USB bandwidth\n");
617 peasycap->video_eof = 1;
618 }
e68703cf 619
c7506658
TW
620 if (isbad) {
621 JOM(4, "attempting cleanup instead of submitting\n");
622 list_for_each(plist_head, (peasycap->purb_video_head)) {
623 pdata_urb = list_entry(plist_head,
624 struct data_urb, list_head);
6888393c 625 if (pdata_urb) {
c7506658 626 purb = pdata_urb->purb;
6888393c 627 if (purb)
c7506658
TW
628 usb_kill_urb(purb);
629 }
702422bd 630 }
c7506658
TW
631 peasycap->video_isoc_streaming = 0;
632 } else {
633 peasycap->video_isoc_streaming = 1;
634 JOM(4, "submitted %i video urbs\n", m);
702422bd 635 }
702422bd 636 } else {
c7506658 637 JOM(4, "already streaming video urbs\n");
702422bd 638 }
c7506658 639 return 0;
702422bd
T
640}
641/*****************************************************************************/
c7506658 642int kill_video_urbs(struct easycap *peasycap)
702422bd 643{
c7506658
TW
644 int m;
645 struct list_head *plist_head;
646 struct data_urb *pdata_urb;
702422bd 647
6888393c 648 if (!peasycap) {
c7506658
TW
649 SAY("ERROR: peasycap is NULL\n");
650 return -EFAULT;
651 }
652 if (!peasycap->video_isoc_streaming) {
653 JOM(8, "%i=video_isoc_streaming, no video urbs killed\n",
654 peasycap->video_isoc_streaming);
655 return 0;
656 }
657 if (!peasycap->purb_video_head) {
e68703cf 658 SAM("ERROR: peasycap->purb_video_head is NULL\n");
702422bd
T
659 return -EFAULT;
660 }
c7506658
TW
661
662 peasycap->video_isoc_streaming = 0;
663 JOM(4, "killing video urbs\n");
664 m = 0;
665 list_for_each(plist_head, (peasycap->purb_video_head)) {
666 pdata_urb = list_entry(plist_head, struct data_urb, list_head);
667 if (pdata_urb && pdata_urb->purb) {
668 usb_kill_urb(pdata_urb->purb);
669 m++;
670 }
671 }
672 JOM(4, "%i video urbs killed\n", m);
673
674 return 0;
702422bd
T
675}
676/****************************************************************************/
702422bd
T
677/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
678/*--------------------------------------------------------------------------*/
d090bf57
TW
679static int easycap_open_noinode(struct file *file)
680{
681 return easycap_open(NULL, file);
682}
683
d090bf57 684static int videodev_release(struct video_device *pvideo_device)
702422bd 685{
c7506658 686 struct easycap *peasycap;
702422bd 687
c7506658 688 peasycap = video_get_drvdata(pvideo_device);
6888393c 689 if (!peasycap) {
c7506658
TW
690 SAY("ERROR: peasycap is NULL\n");
691 SAY("ending unsuccessfully\n");
692 return -EFAULT;
693 }
c7506658
TW
694 if (0 != kill_video_urbs(peasycap)) {
695 SAM("ERROR: kill_video_urbs() failed\n");
696 return -EFAULT;
697 }
698 JOM(4, "ending successfully\n");
699 return 0;
702422bd 700}
e68703cf
MT
701/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
702/*****************************************************************************/
702422bd
T
703/*--------------------------------------------------------------------------*/
704/*
ae59dad4
MT
705 * THIS FUNCTION IS CALLED FROM WITHIN easycap_usb_disconnect() AND IS
706 * PROTECTED BY SEMAPHORES SET AND CLEARED BY easycap_usb_disconnect().
707 *
708 * BY THIS STAGE THE DEVICE HAS ALREADY BEEN PHYSICALLY UNPLUGGED, SO
709 * peasycap->pusb_device IS NO LONGER VALID.
702422bd
T
710 */
711/*---------------------------------------------------------------------------*/
d090bf57 712static void easycap_delete(struct kref *pkref)
702422bd 713{
c7506658
TW
714 struct easycap *peasycap;
715 struct data_urb *pdata_urb;
716 struct list_head *plist_head, *plist_next;
717 int k, m, gone, kd;
718 int allocation_video_urb;
719 int allocation_video_page;
720 int allocation_video_struct;
721 int allocation_audio_urb;
722 int allocation_audio_page;
723 int allocation_audio_struct;
724 int registered_video, registered_audio;
725
726 peasycap = container_of(pkref, struct easycap, kref);
6888393c 727 if (!peasycap) {
c7506658
TW
728 SAM("ERROR: peasycap is NULL: cannot perform deletions\n");
729 return;
730 }
c7506658 731 kd = isdongle(peasycap);
702422bd
T
732/*---------------------------------------------------------------------------*/
733/*
734 * FREE VIDEO.
735 */
736/*---------------------------------------------------------------------------*/
6888393c 737 if (peasycap->purb_video_head) {
c7506658
TW
738 JOM(4, "freeing video urbs\n");
739 m = 0;
740 list_for_each(plist_head, (peasycap->purb_video_head)) {
741 pdata_urb = list_entry(plist_head,
742 struct data_urb, list_head);
6888393c 743 if (!pdata_urb) {
c7506658
TW
744 JOM(4, "ERROR: pdata_urb is NULL\n");
745 } else {
6888393c 746 if (pdata_urb->purb) {
c7506658
TW
747 usb_free_urb(pdata_urb->purb);
748 pdata_urb->purb = NULL;
749 peasycap->allocation_video_urb -= 1;
750 m++;
751 }
702422bd
T
752 }
753 }
702422bd 754
c7506658 755 JOM(4, "%i video urbs freed\n", m);
702422bd 756/*---------------------------------------------------------------------------*/
c7506658
TW
757 JOM(4, "freeing video data_urb structures.\n");
758 m = 0;
759 list_for_each_safe(plist_head, plist_next,
760 peasycap->purb_video_head) {
761 pdata_urb = list_entry(plist_head,
762 struct data_urb, list_head);
763 if (pdata_urb) {
764 peasycap->allocation_video_struct -=
702422bd 765 sizeof(struct data_urb);
c7506658
TW
766 kfree(pdata_urb);
767 pdata_urb = NULL;
768 m++;
769 }
702422bd 770 }
c7506658
TW
771 JOM(4, "%i video data_urb structures freed\n", m);
772 JOM(4, "setting peasycap->purb_video_head=NULL\n");
773 peasycap->purb_video_head = NULL;
702422bd 774 }
702422bd 775/*---------------------------------------------------------------------------*/
c7506658
TW
776 JOM(4, "freeing video isoc buffers.\n");
777 m = 0;
778 for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
779 if (peasycap->video_isoc_buffer[k].pgo) {
780 free_pages((unsigned long)
781 peasycap->video_isoc_buffer[k].pgo,
782 VIDEO_ISOC_ORDER);
783 peasycap->video_isoc_buffer[k].pgo = NULL;
784 peasycap->allocation_video_page -=
785 BIT(VIDEO_ISOC_ORDER);
786 m++;
787 }
702422bd 788 }
c7506658
TW
789 JOM(4, "isoc video buffers freed: %i pages\n",
790 m * (0x01 << VIDEO_ISOC_ORDER));
791/*---------------------------------------------------------------------------*/
792 JOM(4, "freeing video field buffers.\n");
793 gone = 0;
794 for (k = 0; k < FIELD_BUFFER_MANY; k++) {
795 for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
6888393c 796 if (peasycap->field_buffer[k][m].pgo) {
c7506658
TW
797 free_page((unsigned long)
798 peasycap->field_buffer[k][m].pgo);
799 peasycap->field_buffer[k][m].pgo = NULL;
800 peasycap->allocation_video_page -= 1;
801 gone++;
802 }
702422bd
T
803 }
804 }
c7506658
TW
805 JOM(4, "video field buffers freed: %i pages\n", gone);
806/*---------------------------------------------------------------------------*/
807 JOM(4, "freeing video frame buffers.\n");
808 gone = 0;
809 for (k = 0; k < FRAME_BUFFER_MANY; k++) {
810 for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
6888393c 811 if (peasycap->frame_buffer[k][m].pgo) {
c7506658
TW
812 free_page((unsigned long)
813 peasycap->frame_buffer[k][m].pgo);
814 peasycap->frame_buffer[k][m].pgo = NULL;
815 peasycap->allocation_video_page -= 1;
816 gone++;
817 }
702422bd
T
818 }
819 }
c7506658 820 JOM(4, "video frame buffers freed: %i pages\n", gone);
702422bd
T
821/*---------------------------------------------------------------------------*/
822/*
823 * FREE AUDIO.
824 */
825/*---------------------------------------------------------------------------*/
6888393c 826 if (peasycap->purb_audio_head) {
c7506658
TW
827 JOM(4, "freeing audio urbs\n");
828 m = 0;
829 list_for_each(plist_head, (peasycap->purb_audio_head)) {
830 pdata_urb = list_entry(plist_head,
831 struct data_urb, list_head);
6888393c 832 if (!pdata_urb)
c7506658
TW
833 JOM(4, "ERROR: pdata_urb is NULL\n");
834 else {
6888393c 835 if (pdata_urb->purb) {
c7506658
TW
836 usb_free_urb(pdata_urb->purb);
837 pdata_urb->purb = NULL;
838 peasycap->allocation_audio_urb -= 1;
839 m++;
840 }
841 }
842 }
843 JOM(4, "%i audio urbs freed\n", m);
844/*---------------------------------------------------------------------------*/
845 JOM(4, "freeing audio data_urb structures.\n");
846 m = 0;
847 list_for_each_safe(plist_head, plist_next,
848 peasycap->purb_audio_head) {
849 pdata_urb = list_entry(plist_head,
850 struct data_urb, list_head);
851 if (pdata_urb) {
852 peasycap->allocation_audio_struct -=
853 sizeof(struct data_urb);
854 kfree(pdata_urb);
855 pdata_urb = NULL;
702422bd
T
856 m++;
857 }
858 }
c7506658
TW
859 JOM(4, "%i audio data_urb structures freed\n", m);
860 JOM(4, "setting peasycap->purb_audio_head=NULL\n");
861 peasycap->purb_audio_head = NULL;
702422bd 862 }
702422bd 863/*---------------------------------------------------------------------------*/
c7506658 864 JOM(4, "freeing audio isoc buffers.\n");
702422bd 865 m = 0;
c7506658 866 for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
6888393c 867 if (peasycap->audio_isoc_buffer[k].pgo) {
c7506658
TW
868 free_pages((unsigned long)
869 (peasycap->audio_isoc_buffer[k].pgo),
870 AUDIO_ISOC_ORDER);
871 peasycap->audio_isoc_buffer[k].pgo = NULL;
872 peasycap->allocation_audio_page -=
873 BIT(AUDIO_ISOC_ORDER);
702422bd
T
874 m++;
875 }
876 }
c7506658 877 JOM(4, "easyoss_delete(): isoc audio buffers freed: %i pages\n",
702422bd 878 m * (0x01 << AUDIO_ISOC_ORDER));
702422bd 879/*---------------------------------------------------------------------------*/
c7506658
TW
880 JOM(4, "freeing easycap structure.\n");
881 allocation_video_urb = peasycap->allocation_video_urb;
882 allocation_video_page = peasycap->allocation_video_page;
883 allocation_video_struct = peasycap->allocation_video_struct;
884 registered_video = peasycap->registered_video;
885 allocation_audio_urb = peasycap->allocation_audio_urb;
886 allocation_audio_page = peasycap->allocation_audio_page;
887 allocation_audio_struct = peasycap->allocation_audio_struct;
888 registered_audio = peasycap->registered_audio;
889
c7506658
TW
890 if (0 <= kd && DONGLE_MANY > kd) {
891 if (mutex_lock_interruptible(&mutex_dongle)) {
892 SAY("ERROR: cannot down mutex_dongle\n");
893 } else {
894 JOM(4, "locked mutex_dongle\n");
895 easycapdc60_dongle[kd].peasycap = NULL;
896 mutex_unlock(&mutex_dongle);
897 JOM(4, "unlocked mutex_dongle\n");
898 JOT(4, " null-->dongle[%i].peasycap\n", kd);
899 allocation_video_struct -= sizeof(struct easycap);
900 }
a9855917 901 } else {
c7506658
TW
902 SAY("ERROR: cannot purge dongle[].peasycap");
903 }
38d0cffe
DC
904
905 kfree(peasycap);
906
702422bd 907/*---------------------------------------------------------------------------*/
c7506658
TW
908 SAY("%8i=video urbs after all deletions\n", allocation_video_urb);
909 SAY("%8i=video pages after all deletions\n", allocation_video_page);
910 SAY("%8i=video structs after all deletions\n", allocation_video_struct);
911 SAY("%8i=video devices after all deletions\n", registered_video);
912 SAY("%8i=audio urbs after all deletions\n", allocation_audio_urb);
913 SAY("%8i=audio pages after all deletions\n", allocation_audio_page);
914 SAY("%8i=audio structs after all deletions\n", allocation_audio_struct);
915 SAY("%8i=audio devices after all deletions\n", registered_audio);
916
917 JOT(4, "ending.\n");
918 return;
702422bd
T
919}
920/*****************************************************************************/
d090bf57 921static unsigned int easycap_poll(struct file *file, poll_table *wait)
702422bd 922{
c7506658
TW
923 struct easycap *peasycap;
924 int rc, kd;
702422bd 925
c7506658 926 JOT(8, "\n");
702422bd 927
c7506658
TW
928 if (NULL == ((poll_table *)wait))
929 JOT(8, "WARNING: poll table pointer is NULL ... continuing\n");
6888393c 930 if (!file) {
c7506658 931 SAY("ERROR: file pointer is NULL\n");
ae59dad4
MT
932 return -ERESTARTSYS;
933 }
934 peasycap = file->private_data;
6888393c 935 if (!peasycap) {
ae59dad4 936 SAY("ERROR: peasycap is NULL\n");
c7506658 937 return -EFAULT;
ae59dad4 938 }
6888393c 939 if (!peasycap->pusb_device) {
c7506658
TW
940 SAY("ERROR: peasycap->pusb_device is NULL\n");
941 return -EFAULT;
ae59dad4 942 }
c7506658
TW
943/*---------------------------------------------------------------------------*/
944 kd = isdongle(peasycap);
945 if (0 <= kd && DONGLE_MANY > kd) {
946 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
947 SAY("ERROR: cannot down dongle[%i].mutex_video\n", kd);
948 return -ERESTARTSYS;
949 }
950 JOM(4, "locked dongle[%i].mutex_video\n", kd);
951 /*
952 * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER
953 * peasycap, IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
954 * IF NECESSARY, BAIL OUT.
955 */
22f88fcf
AK
956 if (kd != isdongle(peasycap)) {
957 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
c7506658 958 return -ERESTARTSYS;
22f88fcf 959 }
6888393c 960 if (!file) {
c7506658
TW
961 SAY("ERROR: file is NULL\n");
962 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
963 return -ERESTARTSYS;
964 }
965 peasycap = file->private_data;
6888393c 966 if (!peasycap) {
c7506658
TW
967 SAY("ERROR: peasycap is NULL\n");
968 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
969 return -ERESTARTSYS;
970 }
6888393c 971 if (!peasycap->pusb_device) {
c7506658
TW
972 SAM("ERROR: peasycap->pusb_device is NULL\n");
973 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
974 return -ERESTARTSYS;
975 }
976 } else
ae59dad4
MT
977 /*
978 * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap
979 * BEFORE THE ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL
980 * HAVE FAILED. BAIL OUT.
981 */
c7506658
TW
982 return -ERESTARTSYS;
983/*---------------------------------------------------------------------------*/
984 rc = easycap_dqbuf(peasycap, 0);
985 peasycap->polled = 1;
986 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
987 if (0 == rc)
988 return POLLIN | POLLRDNORM;
989 else
990 return POLLERR;
991 }
702422bd
T
992/*****************************************************************************/
993/*---------------------------------------------------------------------------*/
994/*
995 * IF mode IS NONZERO THIS ROUTINE RETURNS -EAGAIN RATHER THAN BLOCKING.
996 */
997/*---------------------------------------------------------------------------*/
c7506658 998int easycap_dqbuf(struct easycap *peasycap, int mode)
702422bd 999{
c7506658 1000 int input, ifield, miss, rc;
702422bd 1001
702422bd 1002
6888393c 1003 if (!peasycap) {
c7506658
TW
1004 SAY("ERROR: peasycap is NULL\n");
1005 return -EFAULT;
1006 }
6888393c 1007 if (!peasycap->pusb_device) {
c7506658
TW
1008 SAY("ERROR: peasycap->pusb_device is NULL\n");
1009 return -EFAULT;
1010 }
1011 ifield = 0;
1012 JOM(8, "%i=ifield\n", ifield);
702422bd 1013/*---------------------------------------------------------------------------*/
849322a0
MT
1014/*
1015 * CHECK FOR LOST INPUT SIGNAL.
1016 *
1017 * FOR THE FOUR-CVBS EasyCAP, THIS DOES NOT WORK AS EXPECTED.
ae59dad4
MT
1018 * IF INPUT 0 IS PRESENT AND SYNC ACQUIRED, UNPLUGGING INPUT 4 DOES NOT
1019 * RESULT IN SETTING BIT 0x40 ON REGISTER 0x1F, PRESUMABLY BECAUSE THERE
1020 * IS FLYWHEELING ON INPUT 0. THE UPSHOT IS:
849322a0
MT
1021 *
1022 * INPUT 0 PLUGGED, INPUT 4 PLUGGED => SCREEN 0 OK, SCREEN 4 OK
1023 * INPUT 0 PLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 OK, SCREEN 4 BLACK
1024 * INPUT 0 UNPLUGGED, INPUT 4 PLUGGED => SCREEN 0 BARS, SCREEN 4 OK
1025 * INPUT 0 UNPLUGGED, INPUT 4 UNPLUGGED => SCREEN 0 BARS, SCREEN 4 BARS
1026*/
1027/*---------------------------------------------------------------------------*/
c7506658
TW
1028 input = peasycap->input;
1029 if (0 <= input && INPUT_MANY > input) {
1030 rc = read_saa(peasycap->pusb_device, 0x1F);
1031 if (0 <= rc) {
1032 if (rc & 0x40)
1033 peasycap->lost[input] += 1;
1034 else
1035 peasycap->lost[input] -= 2;
849322a0 1036
c7506658
TW
1037 if (0 > peasycap->lost[input])
1038 peasycap->lost[input] = 0;
1039 else if ((2 * VIDEO_LOST_TOLERATE) < peasycap->lost[input])
1040 peasycap->lost[input] = (2 * VIDEO_LOST_TOLERATE);
1041 }
849322a0 1042 }
849322a0 1043/*---------------------------------------------------------------------------*/
702422bd 1044/*
40b8d50a 1045 * WAIT FOR FIELD ifield (0 => TOP, 1 => BOTTOM)
702422bd
T
1046 */
1047/*---------------------------------------------------------------------------*/
c7506658
TW
1048 miss = 0;
1049 while ((peasycap->field_read == peasycap->field_fill) ||
1050 (0 != (0xFF00 & peasycap->field_buffer
1dc6e418 1051 [peasycap->field_read][0].kount)) ||
c7506658 1052 (ifield != (0x00FF & peasycap->field_buffer
702422bd 1053 [peasycap->field_read][0].kount))) {
c7506658
TW
1054 if (mode)
1055 return -EAGAIN;
702422bd 1056
a90f3620
TW
1057 JOM(8, "first wait on wq_video, %i=field_read %i=field_fill\n",
1058 peasycap->field_read, peasycap->field_fill);
c7506658
TW
1059
1060 if (0 != (wait_event_interruptible(peasycap->wq_video,
1061 (peasycap->video_idle || peasycap->video_eof ||
1062 ((peasycap->field_read != peasycap->field_fill) &&
a90f3620
TW
1063 (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
1064 (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
c7506658
TW
1065 SAM("aborted by signal\n");
1066 return -EIO;
a90f3620 1067 }
c7506658
TW
1068 if (peasycap->video_idle) {
1069 JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
1070 peasycap->video_idle);
f36bc37a
MT
1071 return -EAGAIN;
1072 }
c7506658
TW
1073 if (peasycap->video_eof) {
1074 JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
1075 #if defined(PERSEVERE)
1076 if (1 == peasycap->status) {
1077 JOM(8, "persevering ...\n");
1078 peasycap->video_eof = 0;
1079 peasycap->audio_eof = 0;
1080 if (0 != reset(peasycap)) {
1081 JOM(8, " ... failed returning -EIO\n");
1082 peasycap->video_eof = 1;
1083 peasycap->audio_eof = 1;
1084 kill_video_urbs(peasycap);
1085 return -EIO;
1086 }
1087 peasycap->status = 0;
1088 JOM(8, " ... OK returning -EAGAIN\n");
1089 return -EAGAIN;
1090 }
1091 #endif /*PERSEVERE*/
1092 peasycap->video_eof = 1;
1093 peasycap->audio_eof = 1;
1094 kill_video_urbs(peasycap);
1095 JOM(8, "returning -EIO\n");
1096 return -EIO;
1097 }
a90f3620 1098 miss++;
702422bd 1099 }
c7506658 1100 JOM(8, "first awakening on wq_video after %i waits\n", miss);
702422bd 1101
c7506658
TW
1102 rc = field2frame(peasycap);
1103 if (rc)
1104 SAM("ERROR: field2frame() rc = %i\n", rc);
702422bd
T
1105/*---------------------------------------------------------------------------*/
1106/*
40b8d50a 1107 * WAIT FOR THE OTHER FIELD
702422bd
T
1108 */
1109/*---------------------------------------------------------------------------*/
c7506658
TW
1110 if (ifield)
1111 ifield = 0;
1112 else
1113 ifield = 1;
1114 miss = 0;
1115 while ((peasycap->field_read == peasycap->field_fill) ||
a90f3620
TW
1116 (0 != (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) ||
1117 (ifield != (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))) {
c7506658
TW
1118 if (mode)
1119 return -EAGAIN;
702422bd 1120
c7506658 1121 JOM(8, "second wait on wq_video %i=field_read %i=field_fill\n",
702422bd 1122 peasycap->field_read, peasycap->field_fill);
c7506658 1123 if (0 != (wait_event_interruptible(peasycap->wq_video,
1dc6e418
TW
1124 (peasycap->video_idle || peasycap->video_eof ||
1125 ((peasycap->field_read != peasycap->field_fill) &&
a90f3620
TW
1126 (0 == (0xFF00 & peasycap->field_buffer[peasycap->field_read][0].kount)) &&
1127 (ifield == (0x00FF & peasycap->field_buffer[peasycap->field_read][0].kount))))))) {
c7506658
TW
1128 SAM("aborted by signal\n");
1129 return -EIO;
1130 }
1131 if (peasycap->video_idle) {
1132 JOM(8, "%i=peasycap->video_idle returning -EAGAIN\n",
f36bc37a 1133 peasycap->video_idle);
f36bc37a
MT
1134 return -EAGAIN;
1135 }
c7506658
TW
1136 if (peasycap->video_eof) {
1137 JOM(8, "%i=peasycap->video_eof\n", peasycap->video_eof);
a90f3620 1138#if defined(PERSEVERE)
c7506658
TW
1139 if (1 == peasycap->status) {
1140 JOM(8, "persevering ...\n");
1141 peasycap->video_eof = 0;
1142 peasycap->audio_eof = 0;
1143 if (0 != reset(peasycap)) {
1144 JOM(8, " ... failed returning -EIO\n");
1145 peasycap->video_eof = 1;
1146 peasycap->audio_eof = 1;
1147 kill_video_urbs(peasycap);
1148 return -EIO;
1149 }
1150 peasycap->status = 0;
1151 JOM(8, " ... OK ... returning -EAGAIN\n");
1152 return -EAGAIN;
1153 }
a90f3620 1154#endif /*PERSEVERE*/
c7506658
TW
1155 peasycap->video_eof = 1;
1156 peasycap->audio_eof = 1;
1157 kill_video_urbs(peasycap);
1158 JOM(8, "returning -EIO\n");
1159 return -EIO;
1160 }
a90f3620 1161 miss++;
702422bd 1162 }
c7506658 1163 JOM(8, "second awakening on wq_video after %i waits\n", miss);
702422bd 1164
c7506658
TW
1165 rc = field2frame(peasycap);
1166 if (rc)
1167 SAM("ERROR: field2frame() rc = %i\n", rc);
40b8d50a
MT
1168/*---------------------------------------------------------------------------*/
1169/*
1170 * WASTE THIS FRAME
1171*/
1172/*---------------------------------------------------------------------------*/
a90f3620 1173 if (peasycap->skip) {
c7506658
TW
1174 peasycap->skipped++;
1175 if (peasycap->skip != peasycap->skipped)
1176 return peasycap->skip - peasycap->skipped;
a90f3620
TW
1177 else
1178 peasycap->skipped = 0;
c7506658 1179 }
40b8d50a 1180/*---------------------------------------------------------------------------*/
c7506658
TW
1181 peasycap->frame_read = peasycap->frame_fill;
1182 peasycap->queued[peasycap->frame_read] = 0;
1183 peasycap->done[peasycap->frame_read] = V4L2_BUF_FLAG_DONE;
702422bd 1184
c7506658
TW
1185 peasycap->frame_fill++;
1186 if (peasycap->frame_buffer_many <= peasycap->frame_fill)
1187 peasycap->frame_fill = 0;
702422bd 1188
c7506658
TW
1189 if (0x01 & easycap_standard[peasycap->standard_offset].mask)
1190 peasycap->frame_buffer[peasycap->frame_read][0].kount =
702422bd 1191 V4L2_FIELD_TOP;
c7506658
TW
1192 else
1193 peasycap->frame_buffer[peasycap->frame_read][0].kount =
702422bd 1194 V4L2_FIELD_BOTTOM;
702422bd 1195
702422bd 1196
c7506658
TW
1197 JOM(8, "setting: %i=peasycap->frame_read\n", peasycap->frame_read);
1198 JOM(8, "bumped to: %i=peasycap->frame_fill\n", peasycap->frame_fill);
1199
1200 return 0;
702422bd
T
1201}
1202/*****************************************************************************/
1203/*---------------------------------------------------------------------------*/
1204/*
1205 * BY DEFINITION, odd IS true FOR THE FIELD OCCUPYING LINES 1,3,5,...,479
1206 * odd IS false FOR THE FIELD OCCUPYING LINES 0,2,4,...,478
1207 *
1208 * WHEN BOOLEAN PARAMETER decimatepixel IS true, ONLY THE FIELD FOR WHICH
1209 * odd==false IS TRANSFERRED TO THE FRAME BUFFER.
1210 *
1211 * THE BOOLEAN PARAMETER offerfields IS true ONLY WHEN THE USER PROGRAM
40b8d50a 1212 * CHOOSES THE OPTION V4L2_FIELD_INTERLACED.
702422bd
T
1213 */
1214/*---------------------------------------------------------------------------*/
1215int
1216field2frame(struct easycap *peasycap)
1217{
c7506658
TW
1218 struct timeval timeval;
1219 long long int above, below;
1220 u32 remainder;
1221 struct signed_div_result sdr;
1222
1223 void *pex, *pad;
1224 int kex, kad, mex, mad, rex, rad, rad2;
1225 int c2, c3, w2, w3, cz, wz;
1226 int rc, bytesperpixel, multiplier;
1227 int much, more, over, rump, caches, input;
1228 u8 mask, margin;
1229 bool odd, isuy, decimatepixel, offerfields, badinput;
1230
6888393c 1231 if (!peasycap) {
c7506658
TW
1232 SAY("ERROR: peasycap is NULL\n");
1233 return -EFAULT;
1234 }
e68703cf 1235
c7506658
TW
1236 badinput = false;
1237 input = 0x07 & peasycap->field_buffer[peasycap->field_read][0].input;
f36bc37a 1238
c7506658
TW
1239 JOM(8, "===== parity %i, input 0x%02X, field buffer %i --> "
1240 "frame buffer %i\n",
1dc6e418
TW
1241 peasycap->field_buffer[peasycap->field_read][0].kount,
1242 peasycap->field_buffer[peasycap->field_read][0].input,
702422bd 1243 peasycap->field_read, peasycap->frame_fill);
c7506658 1244 JOM(8, "===== %i=bytesperpixel\n", peasycap->bytesperpixel);
27d683ab 1245 if (peasycap->offerfields)
c7506658 1246 JOM(8, "===== offerfields\n");
702422bd
T
1247
1248/*---------------------------------------------------------------------------*/
1249/*
1250 * REJECT OR CLEAN BAD FIELDS
1251 */
1252/*---------------------------------------------------------------------------*/
c7506658
TW
1253 if (peasycap->field_read == peasycap->field_fill) {
1254 SAM("ERROR: on entry, still filling field buffer %i\n",
1255 peasycap->field_read);
1256 return 0;
1257 }
3fc0dae8 1258#ifdef EASYCAP_TESTCARD
c7506658 1259 easycap_testcard(peasycap, peasycap->field_read);
702422bd 1260#else
c7506658
TW
1261 if (0 <= input && INPUT_MANY > input) {
1262 if (easycap_bars && VIDEO_LOST_TOLERATE <= peasycap->lost[input])
1263 easycap_testcard(peasycap, peasycap->field_read);
1264 }
702422bd
T
1265#endif /*EASYCAP_TESTCARD*/
1266/*---------------------------------------------------------------------------*/
1267
c7506658
TW
1268 offerfields = peasycap->offerfields;
1269 bytesperpixel = peasycap->bytesperpixel;
1270 decimatepixel = peasycap->decimatepixel;
702422bd 1271
c7506658
TW
1272 if ((2 != bytesperpixel) &&
1273 (3 != bytesperpixel) &&
1274 (4 != bytesperpixel)) {
1275 SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
1276 return -EFAULT;
1277 }
27d683ab 1278 if (decimatepixel)
c7506658
TW
1279 multiplier = 2;
1280 else
1281 multiplier = 1;
702422bd 1282
c7506658
TW
1283 w2 = 2 * multiplier * (peasycap->width);
1284 w3 = bytesperpixel * multiplier * (peasycap->width);
1285 wz = multiplier * (peasycap->height) *
1286 multiplier * (peasycap->width);
1287
1288 kex = peasycap->field_read; mex = 0;
1289 kad = peasycap->frame_fill; mad = 0;
1290
1291 pex = peasycap->field_buffer[kex][0].pgo; rex = PAGE_SIZE;
1292 pad = peasycap->frame_buffer[kad][0].pgo; rad = PAGE_SIZE;
1293 odd = !!(peasycap->field_buffer[kex][0].kount);
1294
febd32bc 1295 if (odd && (!decimatepixel)) {
c7506658
TW
1296 JOM(8, "initial skipping %4i bytes p.%4i\n",
1297 w3/multiplier, mad);
1298 pad += (w3 / multiplier); rad -= (w3 / multiplier);
1299 }
1300 isuy = true;
1301 mask = 0; rump = 0; caches = 0;
1302
1303 cz = 0;
1304 while (cz < wz) {
1305 /*
1306 * PROCESS ONE LINE OF FRAME AT FULL RESOLUTION:
1307 * READ w2 BYTES FROM FIELD BUFFER,
1308 * WRITE w3 BYTES TO FRAME BUFFER
1309 */
febd32bc 1310 if (!decimatepixel) {
c7506658
TW
1311 over = w2;
1312 do {
1313 much = over; more = 0;
1314 margin = 0; mask = 0x00;
1315 if (rex < much)
1316 much = rex;
1317 rump = 0;
1318
1319 if (much % 2) {
1320 SAM("MISTAKE: much is odd\n");
1321 return -EFAULT;
1322 }
702422bd 1323
c7506658
TW
1324 more = (bytesperpixel *
1325 much) / 2;
702422bd 1326/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
c7506658
TW
1327 if (1 < bytesperpixel) {
1328 if (rad * 2 < much * bytesperpixel) {
1329 /*
1330 * INJUDICIOUS ALTERATION OF
1331 * THIS STATEMENT BLOCK WILL
1332 * CAUSE BREAKAGE. BEWARE.
1333 */
1334 rad2 = rad + bytesperpixel - 1;
a90f3620
TW
1335 much = ((((2 * rad2)/bytesperpixel)/2) * 2);
1336 rump = ((bytesperpixel * much) / 2) - rad;
c7506658 1337 more = rad;
a90f3620 1338 }
c7506658
TW
1339 mask = (u8)rump;
1340 margin = 0;
1341 if (much == rex) {
1342 mask |= 0x04;
a90f3620
TW
1343 if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
1344 margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
1345 else
c7506658 1346 mask |= 0x08;
702422bd 1347 }
c7506658
TW
1348 } else {
1349 SAM("MISTAKE: %i=bytesperpixel\n",
1350 bytesperpixel);
1351 return -EFAULT;
702422bd 1352 }
c7506658
TW
1353 if (rump)
1354 caches++;
27d683ab 1355 if (badinput) {
c7506658
TW
1356 JOM(8, "ERROR: 0x%02X=->field_buffer"
1357 "[%i][%i].input, "
1358 "0x%02X=(0x08|->input)\n",
1359 peasycap->field_buffer
1360 [kex][mex].input, kex, mex,
1361 (0x08|peasycap->input));
1362 }
1363 rc = redaub(peasycap, pad, pex, much, more,
1364 mask, margin, isuy);
1365 if (0 > rc) {
1366 SAM("ERROR: redaub() failed\n");
1367 return -EFAULT;
f36bc37a 1368 }
a90f3620
TW
1369 if (much % 4)
1370 isuy = !isuy;
1371
c7506658
TW
1372 over -= much; cz += much;
1373 pex += much; rex -= much;
1374 if (!rex) {
1375 mex++;
1376 pex = peasycap->field_buffer[kex][mex].pgo;
1377 rex = PAGE_SIZE;
a90f3620 1378 if (peasycap->field_buffer[kex][mex].input != (0x08|peasycap->input))
c7506658
TW
1379 badinput = true;
1380 }
1381 pad += more;
1382 rad -= more;
1383 if (!rad) {
1384 mad++;
1385 pad = peasycap->frame_buffer[kad][mad].pgo;
1386 rad = PAGE_SIZE;
1387 if (rump) {
1388 pad += rump;
1389 rad -= rump;
1390 }
1391 }
1392 } while (over);
702422bd
T
1393/*---------------------------------------------------------------------------*/
1394/*
1395 * SKIP w3 BYTES IN TARGET FRAME BUFFER,
1396 * UNLESS IT IS THE LAST LINE OF AN ODD FRAME
1397 */
1398/*---------------------------------------------------------------------------*/
febd32bc 1399 if (!odd || (cz != wz)) {
c7506658
TW
1400 over = w3;
1401 do {
1402 if (!rad) {
1403 mad++;
1404 pad = peasycap->frame_buffer
1405 [kad][mad].pgo;
1406 rad = PAGE_SIZE;
1407 }
1408 more = over;
1409 if (rad < more)
1410 more = rad;
1411 over -= more;
1412 pad += more;
1413 rad -= more;
1414 } while (over);
1415 }
702422bd
T
1416/*---------------------------------------------------------------------------*/
1417/*
1418 * PROCESS ONE LINE OF FRAME AT REDUCED RESOLUTION:
1419 * ONLY IF false==odd,
1420 * READ w2 BYTES FROM FIELD BUFFER,
1421 * WRITE w3 / 2 BYTES TO FRAME BUFFER
1422 */
1423/*---------------------------------------------------------------------------*/
febd32bc 1424 } else if (!odd) {
c7506658
TW
1425 over = w2;
1426 do {
1427 much = over; more = 0; margin = 0; mask = 0x00;
1428 if (rex < much)
1429 much = rex;
1430 rump = 0;
702422bd 1431
c7506658
TW
1432 if (much % 2) {
1433 SAM("MISTAKE: much is odd\n");
1434 return -EFAULT;
1435 }
702422bd 1436
c7506658 1437 more = (bytesperpixel * much) / 4;
702422bd 1438/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
c7506658
TW
1439 if (1 < bytesperpixel) {
1440 if (rad * 4 < much * bytesperpixel) {
1441 /*
1442 * INJUDICIOUS ALTERATION OF
1443 * THIS STATEMENT BLOCK
1444 * WILL CAUSE BREAKAGE.
1445 * BEWARE.
1446 */
1447 rad2 = rad + bytesperpixel - 1;
a90f3620
TW
1448 much = ((((2 * rad2) / bytesperpixel) / 2) * 4);
1449 rump = ((bytesperpixel * much) / 4) - rad;
c7506658 1450 more = rad;
702422bd 1451 }
c7506658
TW
1452 mask = (u8)rump;
1453 margin = 0;
1454 if (much == rex) {
1455 mask |= 0x04;
a90f3620
TW
1456 if ((mex + 1) < FIELD_BUFFER_SIZE / PAGE_SIZE)
1457 margin = *((u8 *)(peasycap->field_buffer[kex][mex + 1].pgo));
1458 else
c7506658 1459 mask |= 0x08;
702422bd
T
1460 }
1461/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1462 } else {
1dc6e418 1463 SAM("MISTAKE: %i=bytesperpixel\n",
702422bd
T
1464 bytesperpixel);
1465 return -EFAULT;
1466 }
1467/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
c7506658
TW
1468 if (rump)
1469 caches++;
1470
27d683ab 1471 if (badinput) {
c7506658
TW
1472 JOM(8, "ERROR: 0x%02X=->field_buffer"
1473 "[%i][%i].input, "
1474 "0x%02X=(0x08|->input)\n",
1475 peasycap->field_buffer
1476 [kex][mex].input, kex, mex,
1477 (0x08|peasycap->input));
1478 }
1479 rc = redaub(peasycap, pad, pex, much, more,
702422bd 1480 mask, margin, isuy);
c7506658
TW
1481 if (0 > rc) {
1482 SAM("ERROR: redaub() failed\n");
1483 return -EFAULT;
702422bd 1484 }
c7506658
TW
1485 over -= much; cz += much;
1486 pex += much; rex -= much;
1487 if (!rex) {
1488 mex++;
1489 pex = peasycap->field_buffer[kex][mex].pgo;
1490 rex = PAGE_SIZE;
1491 if (peasycap->field_buffer[kex][mex].input !=
1492 (0x08|peasycap->input))
1493 badinput = true;
1494 }
1495 pad += more;
1496 rad -= more;
1497 if (!rad) {
1498 mad++;
1499 pad = peasycap->frame_buffer[kad][mad].pgo;
1500 rad = PAGE_SIZE;
1501 if (rump) {
1502 pad += rump;
1503 rad -= rump;
1504 }
1505 }
1506 } while (over);
702422bd
T
1507/*---------------------------------------------------------------------------*/
1508/*
1509 * OTHERWISE JUST
1510 * READ w2 BYTES FROM FIELD BUFFER AND DISCARD THEM
1511 */
1512/*---------------------------------------------------------------------------*/
c7506658
TW
1513 } else {
1514 over = w2;
1515 do {
1516 if (!rex) {
1517 mex++;
1518 pex = peasycap->field_buffer[kex][mex].pgo;
1519 rex = PAGE_SIZE;
1520 if (peasycap->field_buffer[kex][mex].input !=
1521 (0x08|peasycap->input)) {
1522 JOM(8, "ERROR: 0x%02X=->field_buffer"
1523 "[%i][%i].input, "
1524 "0x%02X=(0x08|->input)\n",
1525 peasycap->field_buffer
1526 [kex][mex].input, kex, mex,
1527 (0x08|peasycap->input));
1528 badinput = true;
1529 }
f36bc37a 1530 }
c7506658
TW
1531 much = over;
1532 if (rex < much)
1533 much = rex;
1534 over -= much;
1535 cz += much;
1536 pex += much;
1537 rex -= much;
1538 } while (over);
1539 }
702422bd 1540 }
702422bd
T
1541/*---------------------------------------------------------------------------*/
1542/*
1543 * SANITY CHECKS
1544 */
1545/*---------------------------------------------------------------------------*/
c7506658
TW
1546 c2 = (mex + 1)*PAGE_SIZE - rex;
1547 if (cz != c2)
1548 SAM("ERROR: discrepancy %i in bytes read\n", c2 - cz);
1549 c3 = (mad + 1)*PAGE_SIZE - rad;
1550
febd32bc 1551 if (!decimatepixel) {
c7506658 1552 if (bytesperpixel * cz != c3)
1dc6e418 1553 SAM("ERROR: discrepancy %i in bytes written\n",
c7506658
TW
1554 c3 - (bytesperpixel * cz));
1555 } else {
febd32bc 1556 if (!odd) {
c7506658
TW
1557 if (bytesperpixel *
1558 cz != (4 * c3))
1559 SAM("ERROR: discrepancy %i in bytes written\n",
1560 (2*c3)-(bytesperpixel * cz));
1561 } else {
1562 if (0 != c3)
1563 SAM("ERROR: discrepancy %i "
1564 "in bytes written\n", c3);
1565 }
1566 }
1567 if (rump)
1568 SAM("WORRY: undischarged cache at end of line in frame buffer\n");
702422bd 1569
c7506658
TW
1570 JOM(8, "===== field2frame(): %i bytes --> %i bytes (incl skip)\n", c2, c3);
1571 JOM(8, "===== field2frame(): %i=mad %i=rad\n", mad, rad);
702422bd 1572
27d683ab 1573 if (odd)
c7506658 1574 JOM(8, "+++++ field2frame(): frame buffer %i is full\n", kad);
702422bd 1575
c7506658
TW
1576 if (peasycap->field_read == peasycap->field_fill)
1577 SAM("WARNING: on exit, filling field buffer %i\n",
1578 peasycap->field_read);
702422bd
T
1579/*---------------------------------------------------------------------------*/
1580/*
1581 * CALCULATE VIDEO STREAMING RATE
1582 */
1583/*---------------------------------------------------------------------------*/
c7506658
TW
1584 do_gettimeofday(&timeval);
1585 if (peasycap->timeval6.tv_sec) {
1586 below = ((long long int)(1000000)) *
1587 ((long long int)(timeval.tv_sec -
1588 peasycap->timeval6.tv_sec)) +
1589 (long long int)(timeval.tv_usec - peasycap->timeval6.tv_usec);
1590 above = (long long int)1000000;
702422bd 1591
c7506658
TW
1592 sdr = signed_div(above, below);
1593 above = sdr.quotient;
1594 remainder = (u32)sdr.remainder;
702422bd 1595
c7506658
TW
1596 JOM(8, "video streaming at %3lli.%03i fields per second\n",
1597 above, (remainder/1000));
1598 }
1599 peasycap->timeval6 = timeval;
702422bd 1600
c7506658
TW
1601 if (caches)
1602 JOM(8, "%i=caches\n", caches);
1603 return 0;
702422bd
T
1604}
1605/*****************************************************************************/
1606struct signed_div_result
1607signed_div(long long int above, long long int below)
1608{
c7506658
TW
1609 struct signed_div_result sdr;
1610
1611 if (((0 <= above) && (0 <= below)) || ((0 > above) && (0 > below))) {
1612 sdr.remainder = (unsigned long long int) do_div(above, below);
1613 sdr.quotient = (long long int) above;
1614 } else {
1615 if (0 > above)
1616 above = -above;
1617 if (0 > below)
1618 below = -below;
1619 sdr.remainder = (unsigned long long int) do_div(above, below);
1620 sdr.quotient = -((long long int) above);
1621 }
1622 return sdr;
702422bd
T
1623}
1624/*****************************************************************************/
1625/*---------------------------------------------------------------------------*/
1626/*
1627 * DECIMATION AND COLOURSPACE CONVERSION.
1628 *
1629 * THIS ROUTINE REQUIRES THAT ALL THE DATA TO BE READ RESIDES ON ONE PAGE
1630 * AND THAT ALL THE DATA TO BE WRITTEN RESIDES ON ONE (DIFFERENT) PAGE.
1631 * THE CALLING ROUTINE MUST ENSURE THAT THIS REQUIREMENT IS MET, AND MUST
1632 * ALSO ENSURE THAT much IS EVEN.
1633 *
1634 * much BYTES ARE READ, AT LEAST (bytesperpixel * much)/2 BYTES ARE WRITTEN
1635 * IF THERE IS NO DECIMATION, HALF THIS AMOUNT IF THERE IS DECIMATION.
1636 *
1637 * mask IS ZERO WHEN NO SPECIAL BEHAVIOUR REQUIRED. OTHERWISE IT IS SET THUS:
1638 * 0x03 & mask = number of bytes to be written to cache instead of to
1639 * frame buffer
1640 * 0x04 & mask => use argument margin to set the chrominance for last pixel
1641 * 0x08 & mask => do not set the chrominance for last pixel
1642 *
1643 * YUV to RGB CONVERSION IS (OR SHOULD BE) ITU-R BT 601.
1644 *
1645 * THERE IS A LOT OF CODE REPETITION IN THIS ROUTINE IN ORDER TO AVOID
1646 * INEFFICIENT SWITCHING INSIDE INNER LOOPS. REARRANGING THE LOGIC TO
1647 * REDUCE CODE LENGTH WILL GENERALLY IMPAIR RUNTIME PERFORMANCE. BEWARE.
1648 */
1649/*---------------------------------------------------------------------------*/
1650int
1dc6e418 1651redaub(struct easycap *peasycap, void *pad, void *pex, int much, int more,
055e3a3a 1652 u8 mask, u8 margin, bool isuy)
702422bd 1653{
c7506658
TW
1654 static s32 ay[256], bu[256], rv[256], gu[256], gv[256];
1655 u8 *pcache;
1656 u8 r, g, b, y, u, v, c, *p2, *p3, *pz, *pr;
1657 int bytesperpixel;
1658 bool byteswaporder, decimatepixel, last;
1659 int j, rump;
1660 s32 tmp;
1661
1662 if (much % 2) {
1663 SAM("MISTAKE: much is odd\n");
1664 return -EFAULT;
1665 }
1666 bytesperpixel = peasycap->bytesperpixel;
1667 byteswaporder = peasycap->byteswaporder;
1668 decimatepixel = peasycap->decimatepixel;
1669
1670/*---------------------------------------------------------------------------*/
1671 if (!bu[255]) {
1672 for (j = 0; j < 112; j++) {
1673 tmp = (0xFF00 & (453 * j)) >> 8;
1674 bu[j + 128] = tmp; bu[127 - j] = -tmp;
1675 tmp = (0xFF00 & (359 * j)) >> 8;
1676 rv[j + 128] = tmp; rv[127 - j] = -tmp;
1677 tmp = (0xFF00 & (88 * j)) >> 8;
1678 gu[j + 128] = tmp; gu[127 - j] = -tmp;
1679 tmp = (0xFF00 & (183 * j)) >> 8;
1680 gv[j + 128] = tmp; gv[127 - j] = -tmp;
1681 }
1682 for (j = 0; j < 16; j++) {
1683 bu[j] = bu[16]; rv[j] = rv[16];
1684 gu[j] = gu[16]; gv[j] = gv[16];
1685 }
1686 for (j = 240; j < 256; j++) {
1687 bu[j] = bu[239]; rv[j] = rv[239];
1688 gu[j] = gu[239]; gv[j] = gv[239];
1689 }
1690 for (j = 16; j < 236; j++)
1691 ay[j] = j;
1692 for (j = 0; j < 16; j++)
1693 ay[j] = ay[16];
1694 for (j = 236; j < 256; j++)
1695 ay[j] = ay[235];
1696 JOM(8, "lookup tables are prepared\n");
1697 }
1698 pcache = peasycap->pcache;
6888393c 1699 if (!pcache)
c7506658 1700 pcache = &peasycap->cache[0];
702422bd
T
1701/*---------------------------------------------------------------------------*/
1702/*
1703 * TRANSFER CONTENTS OF CACHE TO THE FRAME BUFFER
1704 */
1705/*---------------------------------------------------------------------------*/
c7506658
TW
1706 if (!pcache) {
1707 SAM("MISTAKE: pcache is NULL\n");
1708 return -EFAULT;
1709 }
702422bd 1710
c7506658
TW
1711 if (pcache != &peasycap->cache[0])
1712 JOM(16, "cache has %i bytes\n", (int)(pcache - &peasycap->cache[0]));
1713 p2 = &peasycap->cache[0];
1714 p3 = (u8 *)pad - (int)(pcache - &peasycap->cache[0]);
1715 while (p2 < pcache) {
1716 *p3++ = *p2; p2++;
1717 }
1718 pcache = &peasycap->cache[0];
1719 if (p3 != pad) {
1720 SAM("MISTAKE: pointer misalignment\n");
1721 return -EFAULT;
1722 }
702422bd 1723/*---------------------------------------------------------------------------*/
c7506658
TW
1724 rump = (int)(0x03 & mask);
1725 u = 0; v = 0;
1726 p2 = (u8 *)pex; pz = p2 + much; pr = p3 + more; last = false;
1727 p2++;
702422bd 1728
27d683ab 1729 if (isuy)
c7506658
TW
1730 u = *(p2 - 1);
1731 else
1732 v = *(p2 - 1);
702422bd 1733
c7506658
TW
1734 if (rump)
1735 JOM(16, "%4i=much %4i=more %i=rump\n", much, more, rump);
702422bd
T
1736
1737/*---------------------------------------------------------------------------*/
c7506658
TW
1738 switch (bytesperpixel) {
1739 case 2: {
febd32bc 1740 if (!decimatepixel) {
c7506658 1741 memcpy(pad, pex, (size_t)much);
febd32bc 1742 if (!byteswaporder) {
c7506658
TW
1743 /* UYVY */
1744 return 0;
1745 } else {
1746 /* YUYV */
1747 p3 = (u8 *)pad; pz = p3 + much;
1748 while (pz > p3) {
1749 c = *p3;
1750 *p3 = *(p3 + 1);
1751 *(p3 + 1) = c;
1752 p3 += 2;
702422bd 1753 }
c7506658 1754 return 0;
702422bd 1755 }
702422bd 1756 } else {
febd32bc 1757 if (!byteswaporder) {
c7506658
TW
1758 /* UYVY DECIMATED */
1759 p2 = (u8 *)pex; p3 = (u8 *)pad; pz = p2 + much;
1760 while (pz > p2) {
1761 *p3 = *p2;
1762 *(p3 + 1) = *(p2 + 1);
1763 *(p3 + 2) = *(p2 + 2);
1764 *(p3 + 3) = *(p2 + 3);
1765 p3 += 4; p2 += 8;
702422bd 1766 }
c7506658
TW
1767 return 0;
1768 } else {
1769 /* YUYV DECIMATED */
1770 p2 = (u8 *)pex; p3 = (u8 *)pad; pz = p2 + much;
1771 while (pz > p2) {
1772 *p3 = *(p2 + 1);
1773 *(p3 + 1) = *p2;
1774 *(p3 + 2) = *(p2 + 3);
1775 *(p3 + 3) = *(p2 + 2);
1776 p3 += 4; p2 += 8;
702422bd 1777 }
c7506658 1778 return 0;
702422bd 1779 }
c7506658
TW
1780 }
1781 break;
1782 }
1783 case 3:
1784 {
febd32bc
TW
1785 if (!decimatepixel) {
1786 if (!byteswaporder) {
c7506658
TW
1787 /* RGB */
1788 while (pz > p2) {
1789 if (pr <= (p3 + bytesperpixel))
1790 last = true;
1791 else
1792 last = false;
1793 y = *p2;
27d683ab 1794 if (last && (0x0C & mask)) {
c7506658 1795 if (0x04 & mask) {
27d683ab 1796 if (isuy)
c7506658
TW
1797 v = margin;
1798 else
1799 u = margin;
1800 } else
1801 if (0x08 & mask)
1802 ;
1803 } else {
27d683ab 1804 if (isuy)
c7506658 1805 v = *(p2 + 1);
702422bd 1806 else
c7506658
TW
1807 u = *(p2 + 1);
1808 }
702422bd 1809
27d17669
TW
1810 tmp = ay[(int)y] + rv[(int)v];
1811 r = (255 < tmp) ? 255 : ((0 > tmp) ?
055e3a3a 1812 0 : (u8)tmp);
c7506658 1813 tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
27d17669 1814 g = (255 < tmp) ? 255 : ((0 > tmp) ?
055e3a3a 1815 0 : (u8)tmp);
27d17669
TW
1816 tmp = ay[(int)y] + bu[(int)u];
1817 b = (255 < tmp) ? 255 : ((0 > tmp) ?
055e3a3a 1818 0 : (u8)tmp);
702422bd 1819
27d683ab 1820 if (last && rump) {
e68703cf 1821 pcache = &peasycap->cache[0];
702422bd
T
1822 switch (bytesperpixel - rump) {
1823 case 1: {
1824 *p3 = r;
1825 *pcache++ = g;
1826 *pcache++ = b;
1827 break;
1828 }
1829 case 2: {
1830 *p3 = r;
1831 *(p3 + 1) = g;
1832 *pcache++ = b;
1833 break;
1834 }
1835 default: {
c7506658
TW
1836 SAM("MISTAKE: %i=rump\n",
1837 bytesperpixel - rump);
702422bd
T
1838 return -EFAULT;
1839 }
1840 }
1841 } else {
1842 *p3 = r;
1843 *(p3 + 1) = g;
1844 *(p3 + 2) = b;
1845 }
c7506658 1846 p2 += 2;
27d683ab 1847 if (isuy)
c7506658
TW
1848 isuy = false;
1849 else
1850 isuy = true;
702422bd 1851 p3 += bytesperpixel;
702422bd 1852 }
c7506658
TW
1853 return 0;
1854 } else {
1855 /* BGR */
1856 while (pz > p2) {
1857 if (pr <= (p3 + bytesperpixel))
1858 last = true;
1859 else
1860 last = false;
1861 y = *p2;
27d683ab 1862 if (last && (0x0C & mask)) {
c7506658 1863 if (0x04 & mask) {
27d683ab 1864 if (isuy)
c7506658
TW
1865 v = margin;
1866 else
1867 u = margin;
1868 }
1869 else
702422bd
T
1870 if (0x08 & mask)
1871 ;
c7506658 1872 } else {
27d683ab 1873 if (isuy)
c7506658
TW
1874 v = *(p2 + 1);
1875 else
1876 u = *(p2 + 1);
1877 }
702422bd 1878
27d17669
TW
1879 tmp = ay[(int)y] + rv[(int)v];
1880 r = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658
TW
1881 0 : (u8)tmp);
1882 tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
27d17669 1883 g = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658 1884 0 : (u8)tmp);
27d17669
TW
1885 tmp = ay[(int)y] + bu[(int)u];
1886 b = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658 1887 0 : (u8)tmp);
702422bd 1888
27d683ab 1889 if (last && rump) {
e68703cf 1890 pcache = &peasycap->cache[0];
702422bd
T
1891 switch (bytesperpixel - rump) {
1892 case 1: {
1893 *p3 = b;
1894 *pcache++ = g;
1895 *pcache++ = r;
1896 break;
1897 }
1898 case 2: {
1899 *p3 = b;
1900 *(p3 + 1) = g;
1901 *pcache++ = r;
1902 break;
1903 }
1904 default: {
c7506658
TW
1905 SAM("MISTAKE: %i=rump\n",
1906 bytesperpixel - rump);
702422bd
T
1907 return -EFAULT;
1908 }
1909 }
1910 } else {
1911 *p3 = b;
1912 *(p3 + 1) = g;
1913 *(p3 + 2) = r;
1914 }
c7506658 1915 p2 += 2;
27d683ab 1916 if (isuy)
c7506658
TW
1917 isuy = false;
1918 else
1919 isuy = true;
702422bd
T
1920 p3 += bytesperpixel;
1921 }
702422bd
T
1922 }
1923 return 0;
c7506658 1924 } else {
febd32bc 1925 if (!byteswaporder) {
c7506658
TW
1926 /* RGB DECIMATED */
1927 while (pz > p2) {
1928 if (pr <= (p3 + bytesperpixel))
1929 last = true;
1930 else
1931 last = false;
1932 y = *p2;
27d683ab 1933 if (last && (0x0C & mask)) {
c7506658 1934 if (0x04 & mask) {
27d683ab 1935 if (isuy)
c7506658
TW
1936 v = margin;
1937 else
1938 u = margin;
1939 } else
1940 if (0x08 & mask)
1941 ;
1942 } else {
27d683ab 1943 if (isuy)
c7506658 1944 v = *(p2 + 1);
702422bd 1945 else
c7506658 1946 u = *(p2 + 1);
702422bd 1947 }
c7506658 1948
27d683ab 1949 if (isuy) {
c7506658
TW
1950 tmp = ay[(int)y] + rv[(int)v];
1951 r = (255 < tmp) ? 255 : ((0 > tmp) ?
1952 0 : (u8)tmp);
1953 tmp = ay[(int)y] - gu[(int)u] -
1954 gv[(int)v];
1955 g = (255 < tmp) ? 255 : ((0 > tmp) ?
1956 0 : (u8)tmp);
1957 tmp = ay[(int)y] + bu[(int)u];
1958 b = (255 < tmp) ? 255 : ((0 > tmp) ?
1959 0 : (u8)tmp);
1960
27d683ab 1961 if (last && rump) {
c7506658
TW
1962 pcache = &peasycap->cache[0];
1963 switch (bytesperpixel - rump) {
1964 case 1: {
1965 *p3 = r;
1966 *pcache++ = g;
1967 *pcache++ = b;
1968 break;
1969 }
1970 case 2: {
1971 *p3 = r;
1972 *(p3 + 1) = g;
1973 *pcache++ = b;
1974 break;
1975 }
1976 default: {
1977 SAM("MISTAKE: "
1978 "%i=rump\n",
1979 bytesperpixel - rump);
1980 return -EFAULT;
1981 }
1982 }
1983 } else {
1984 *p3 = r;
1985 *(p3 + 1) = g;
1986 *(p3 + 2) = b;
1987 }
1988 isuy = false;
1989 p3 += bytesperpixel;
1990 } else {
1991 isuy = true;
702422bd 1992 }
c7506658 1993 p2 += 2;
702422bd 1994 }
c7506658
TW
1995 return 0;
1996 } else {
1997 /* BGR DECIMATED */
1998 while (pz > p2) {
1999 if (pr <= (p3 + bytesperpixel))
2000 last = true;
2001 else
2002 last = false;
2003 y = *p2;
27d683ab 2004 if (last && (0x0C & mask)) {
c7506658 2005 if (0x04 & mask) {
27d683ab 2006 if (isuy)
c7506658
TW
2007 v = margin;
2008 else
2009 u = margin;
2010 } else
2011 if (0x08 & mask)
2012 ;
2013 } else {
27d683ab 2014 if (isuy)
c7506658 2015 v = *(p2 + 1);
702422bd 2016 else
c7506658 2017 u = *(p2 + 1);
702422bd 2018 }
c7506658 2019
27d683ab 2020 if (isuy) {
c7506658
TW
2021
2022 tmp = ay[(int)y] + rv[(int)v];
2023 r = (255 < tmp) ? 255 : ((0 > tmp) ?
2024 0 : (u8)tmp);
2025 tmp = ay[(int)y] - gu[(int)u] -
2026 gv[(int)v];
2027 g = (255 < tmp) ? 255 : ((0 > tmp) ?
2028 0 : (u8)tmp);
2029 tmp = ay[(int)y] + bu[(int)u];
2030 b = (255 < tmp) ? 255 : ((0 > tmp) ?
2031 0 : (u8)tmp);
2032
27d683ab 2033 if (last && rump) {
c7506658
TW
2034 pcache = &peasycap->cache[0];
2035 switch (bytesperpixel - rump) {
2036 case 1: {
2037 *p3 = b;
2038 *pcache++ = g;
2039 *pcache++ = r;
2040 break;
2041 }
2042 case 2: {
2043 *p3 = b;
2044 *(p3 + 1) = g;
2045 *pcache++ = r;
2046 break;
2047 }
2048 default: {
2049 SAM("MISTAKE: "
2050 "%i=rump\n",
2051 bytesperpixel - rump);
2052 return -EFAULT;
2053 }
2054 }
2055 } else {
2056 *p3 = b;
2057 *(p3 + 1) = g;
2058 *(p3 + 2) = r;
2059 }
2060 isuy = false;
2061 p3 += bytesperpixel;
2062 }
2063 else
2064 isuy = true;
2065 p2 += 2;
702422bd 2066 }
c7506658 2067 return 0;
702422bd 2068 }
702422bd 2069 }
c7506658 2070 break;
702422bd 2071 }
c7506658
TW
2072 case 4:
2073 {
febd32bc
TW
2074 if (!decimatepixel) {
2075 if (!byteswaporder) {
c7506658
TW
2076 /* RGBA */
2077 while (pz > p2) {
2078 if (pr <= (p3 + bytesperpixel))
2079 last = true;
2080 else
2081 last = false;
2082 y = *p2;
27d683ab 2083 if (last && (0x0C & mask)) {
c7506658 2084 if (0x04 & mask) {
27d683ab 2085 if (isuy)
c7506658
TW
2086 v = margin;
2087 else
2088 u = margin;
2089 } else
2090 if (0x08 & mask)
2091 ;
2092 } else {
27d683ab 2093 if (isuy)
c7506658 2094 v = *(p2 + 1);
702422bd 2095 else
c7506658
TW
2096 u = *(p2 + 1);
2097 }
702422bd 2098
27d17669
TW
2099 tmp = ay[(int)y] + rv[(int)v];
2100 r = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658
TW
2101 0 : (u8)tmp);
2102 tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
27d17669 2103 g = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658 2104 0 : (u8)tmp);
27d17669
TW
2105 tmp = ay[(int)y] + bu[(int)u];
2106 b = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658 2107 0 : (u8)tmp);
702422bd 2108
27d683ab 2109 if (last && rump) {
e68703cf 2110 pcache = &peasycap->cache[0];
702422bd
T
2111 switch (bytesperpixel - rump) {
2112 case 1: {
2113 *p3 = r;
2114 *pcache++ = g;
2115 *pcache++ = b;
2116 *pcache++ = 0;
2117 break;
2118 }
2119 case 2: {
2120 *p3 = r;
2121 *(p3 + 1) = g;
2122 *pcache++ = b;
2123 *pcache++ = 0;
2124 break;
2125 }
2126 case 3: {
2127 *p3 = r;
2128 *(p3 + 1) = g;
2129 *(p3 + 2) = b;
2130 *pcache++ = 0;
2131 break;
2132 }
2133 default: {
c7506658
TW
2134 SAM("MISTAKE: %i=rump\n",
2135 bytesperpixel - rump);
702422bd 2136 return -EFAULT;
c7506658 2137 }
702422bd
T
2138 }
2139 } else {
2140 *p3 = r;
2141 *(p3 + 1) = g;
2142 *(p3 + 2) = b;
2143 *(p3 + 3) = 0;
c7506658
TW
2144 }
2145 p2 += 2;
27d683ab 2146 if (isuy)
c7506658 2147 isuy = false;
702422bd 2148 else
c7506658
TW
2149 isuy = true;
2150 p3 += bytesperpixel;
702422bd 2151 }
c7506658
TW
2152 return 0;
2153 } else {
2154 /*
2155 * BGRA
2156 */
2157 while (pz > p2) {
2158 if (pr <= (p3 + bytesperpixel))
2159 last = true;
2160 else
2161 last = false;
2162 y = *p2;
27d683ab 2163 if (last && (0x0C & mask)) {
c7506658 2164 if (0x04 & mask) {
27d683ab 2165 if (isuy)
c7506658
TW
2166 v = margin;
2167 else
2168 u = margin;
2169 } else
2170 if (0x08 & mask)
2171 ;
2172 } else {
27d683ab 2173 if (isuy)
c7506658
TW
2174 v = *(p2 + 1);
2175 else
2176 u = *(p2 + 1);
2177 }
702422bd 2178
27d17669
TW
2179 tmp = ay[(int)y] + rv[(int)v];
2180 r = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658
TW
2181 0 : (u8)tmp);
2182 tmp = ay[(int)y] - gu[(int)u] - gv[(int)v];
27d17669 2183 g = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658 2184 0 : (u8)tmp);
27d17669
TW
2185 tmp = ay[(int)y] + bu[(int)u];
2186 b = (255 < tmp) ? 255 : ((0 > tmp) ?
c7506658 2187 0 : (u8)tmp);
702422bd 2188
27d683ab 2189 if (last && rump) {
e68703cf 2190 pcache = &peasycap->cache[0];
702422bd
T
2191 switch (bytesperpixel - rump) {
2192 case 1: {
2193 *p3 = b;
2194 *pcache++ = g;
2195 *pcache++ = r;
2196 *pcache++ = 0;
2197 break;
2198 }
2199 case 2: {
2200 *p3 = b;
2201 *(p3 + 1) = g;
2202 *pcache++ = r;
2203 *pcache++ = 0;
2204 break;
2205 }
2206 case 3: {
2207 *p3 = b;
2208 *(p3 + 1) = g;
2209 *(p3 + 2) = r;
2210 *pcache++ = 0;
2211 break;
2212 }
c7506658
TW
2213 default:
2214 SAM("MISTAKE: %i=rump\n",
2215 bytesperpixel - rump);
702422bd
T
2216 return -EFAULT;
2217 }
702422bd
T
2218 } else {
2219 *p3 = b;
2220 *(p3 + 1) = g;
2221 *(p3 + 2) = r;
2222 *(p3 + 3) = 0;
2223 }
c7506658 2224 p2 += 2;
27d683ab 2225 if (isuy)
c7506658
TW
2226 isuy = false;
2227 else
2228 isuy = true;
702422bd 2229 p3 += bytesperpixel;
c7506658
TW
2230 }
2231 }
2232 return 0;
2233 } else {
febd32bc 2234 if (!byteswaporder) {
c7506658
TW
2235 /*
2236 * RGBA DECIMATED
2237 */
2238 while (pz > p2) {
2239 if (pr <= (p3 + bytesperpixel))
2240 last = true;
2241 else
2242 last = false;
2243 y = *p2;
27d683ab 2244 if (last && (0x0C & mask)) {
c7506658 2245 if (0x04 & mask) {
27d683ab 2246 if (isuy)
c7506658
TW
2247 v = margin;
2248 else
2249 u = margin;
2250 } else
2251 if (0x08 & mask)
2252 ;
2253 } else {
27d683ab 2254 if (isuy)
c7506658
TW
2255 v = *(p2 + 1);
2256 else
2257 u = *(p2 + 1);
2258 }
2259
27d683ab 2260 if (isuy) {
c7506658
TW
2261
2262 tmp = ay[(int)y] + rv[(int)v];
2263 r = (255 < tmp) ? 255 : ((0 > tmp) ?
2264 0 : (u8)tmp);
2265 tmp = ay[(int)y] - gu[(int)u] -
2266 gv[(int)v];
2267 g = (255 < tmp) ? 255 : ((0 > tmp) ?
2268 0 : (u8)tmp);
2269 tmp = ay[(int)y] + bu[(int)u];
2270 b = (255 < tmp) ? 255 : ((0 > tmp) ?
2271 0 : (u8)tmp);
2272
27d683ab 2273 if (last && rump) {
c7506658
TW
2274 pcache = &peasycap->cache[0];
2275 switch (bytesperpixel - rump) {
2276 case 1: {
2277 *p3 = r;
2278 *pcache++ = g;
2279 *pcache++ = b;
2280 *pcache++ = 0;
2281 break;
2282 }
2283 case 2: {
2284 *p3 = r;
2285 *(p3 + 1) = g;
2286 *pcache++ = b;
2287 *pcache++ = 0;
2288 break;
2289 }
2290 case 3: {
2291 *p3 = r;
2292 *(p3 + 1) = g;
2293 *(p3 + 2) = b;
2294 *pcache++ = 0;
2295 break;
2296 }
2297 default: {
2298 SAM("MISTAKE: "
2299 "%i=rump\n",
2300 bytesperpixel -
2301 rump);
2302 return -EFAULT;
2303 }
2304 }
2305 } else {
2306 *p3 = r;
2307 *(p3 + 1) = g;
2308 *(p3 + 2) = b;
2309 *(p3 + 3) = 0;
2310 }
2311 isuy = false;
2312 p3 += bytesperpixel;
2313 } else
2314 isuy = true;
702422bd
T
2315 p2 += 2;
2316 }
c7506658
TW
2317 return 0;
2318 } else {
2319 /*
2320 * BGRA DECIMATED
2321 */
2322 while (pz > p2) {
2323 if (pr <= (p3 + bytesperpixel))
2324 last = true;
2325 else
2326 last = false;
2327 y = *p2;
27d683ab 2328 if (last && (0x0C & mask)) {
c7506658 2329 if (0x04 & mask) {
27d683ab 2330 if (isuy)
c7506658
TW
2331 v = margin;
2332 else
2333 u = margin;
2334 } else
2335 if (0x08 & mask)
2336 ;
2337 } else {
27d683ab 2338 if (isuy)
c7506658
TW
2339 v = *(p2 + 1);
2340 else
2341 u = *(p2 + 1);
2342 }
2343
27d683ab 2344 if (isuy) {
c7506658
TW
2345 tmp = ay[(int)y] + rv[(int)v];
2346 r = (255 < tmp) ? 255 : ((0 > tmp) ?
2347 0 : (u8)tmp);
2348 tmp = ay[(int)y] - gu[(int)u] -
2349 gv[(int)v];
2350 g = (255 < tmp) ? 255 : ((0 > tmp) ?
2351 0 : (u8)tmp);
2352 tmp = ay[(int)y] + bu[(int)u];
2353 b = (255 < tmp) ? 255 : ((0 > tmp) ?
2354 0 : (u8)tmp);
2355
27d683ab 2356 if (last && rump) {
c7506658
TW
2357 pcache = &peasycap->cache[0];
2358 switch (bytesperpixel - rump) {
2359 case 1: {
2360 *p3 = b;
2361 *pcache++ = g;
2362 *pcache++ = r;
2363 *pcache++ = 0;
2364 break;
2365 }
2366 case 2: {
2367 *p3 = b;
2368 *(p3 + 1) = g;
2369 *pcache++ = r;
2370 *pcache++ = 0;
2371 break;
2372 }
2373 case 3: {
2374 *p3 = b;
2375 *(p3 + 1) = g;
2376 *(p3 + 2) = r;
2377 *pcache++ = 0;
2378 break;
2379 }
2380 default: {
2381 SAM("MISTAKE: "
2382 "%i=rump\n",
2383 bytesperpixel - rump);
2384 return -EFAULT;
2385 }
2386 }
2387 } else {
2388 *p3 = b;
2389 *(p3 + 1) = g;
2390 *(p3 + 2) = r;
2391 *(p3 + 3) = 0;
2392 }
2393 isuy = false;
2394 p3 += bytesperpixel;
2395 } else
2396 isuy = true;
2397 p2 += 2;
2398 }
2399 return 0;
2400 }
702422bd 2401 }
c7506658
TW
2402 break;
2403 }
2404 default: {
2405 SAM("MISTAKE: %i=bytesperpixel\n", bytesperpixel);
2406 return -EFAULT;
702422bd 2407 }
702422bd 2408 }
c7506658 2409 return 0;
702422bd
T
2410}
2411/*****************************************************************************/
702422bd
T
2412/*
2413 * SEE CORBET ET AL. "LINUX DEVICE DRIVERS", 3rd EDITION, PAGES 430-434
2414 */
702422bd 2415/*****************************************************************************/
d090bf57 2416static void easycap_vma_open(struct vm_area_struct *pvma)
702422bd 2417{
c7506658 2418 struct easycap *peasycap;
702422bd 2419
c7506658 2420 peasycap = pvma->vm_private_data;
6888393c 2421 if (!peasycap) {
c7506658
TW
2422 SAY("ERROR: peasycap is NULL\n");
2423 return;
2424 }
c7506658
TW
2425 peasycap->vma_many++;
2426 JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
268dfede
MT
2427 return;
2428}
702422bd 2429/*****************************************************************************/
d090bf57 2430static void easycap_vma_close(struct vm_area_struct *pvma)
702422bd 2431{
c7506658 2432 struct easycap *peasycap;
702422bd 2433
c7506658 2434 peasycap = pvma->vm_private_data;
6888393c 2435 if (!peasycap) {
c7506658
TW
2436 SAY("ERROR: peasycap is NULL\n");
2437 return;
2438 }
c7506658
TW
2439 peasycap->vma_many--;
2440 JOT(8, "%i=peasycap->vma_many\n", peasycap->vma_many);
268dfede 2441 return;
702422bd 2442}
702422bd 2443/*****************************************************************************/
d090bf57 2444static int easycap_vma_fault(struct vm_area_struct *pvma, struct vm_fault *pvmf)
702422bd 2445{
c7506658
TW
2446 int k, m, retcode;
2447 void *pbuf;
2448 struct page *page;
2449 struct easycap *peasycap;
702422bd 2450
c7506658 2451 retcode = VM_FAULT_NOPAGE;
702422bd 2452
6888393c 2453 if (!pvma) {
c7506658
TW
2454 SAY("pvma is NULL\n");
2455 return retcode;
2456 }
6888393c 2457 if (!pvmf) {
c7506658
TW
2458 SAY("pvmf is NULL\n");
2459 return retcode;
2460 }
702422bd 2461
c7506658
TW
2462 k = (pvmf->pgoff) / (FRAME_BUFFER_SIZE/PAGE_SIZE);
2463 m = (pvmf->pgoff) % (FRAME_BUFFER_SIZE/PAGE_SIZE);
702422bd 2464
c7506658
TW
2465 if (!m)
2466 JOT(4, "%4i=k, %4i=m\n", k, m);
2467 else
2468 JOT(16, "%4i=k, %4i=m\n", k, m);
702422bd 2469
c7506658
TW
2470 if ((0 > k) || (FRAME_BUFFER_MANY <= k)) {
2471 SAY("ERROR: buffer index %i out of range\n", k);
2472 return retcode;
2473 }
2474 if ((0 > m) || (FRAME_BUFFER_SIZE/PAGE_SIZE <= m)) {
2475 SAY("ERROR: page number %i out of range\n", m);
2476 return retcode;
2477 }
2478 peasycap = pvma->vm_private_data;
6888393c 2479 if (!peasycap) {
c7506658
TW
2480 SAY("ERROR: peasycap is NULL\n");
2481 return retcode;
2482 }
702422bd 2483/*---------------------------------------------------------------------------*/
c7506658 2484 pbuf = peasycap->frame_buffer[k][m].pgo;
6888393c 2485 if (!pbuf) {
c7506658
TW
2486 SAM("ERROR: pbuf is NULL\n");
2487 return retcode;
2488 }
2489 page = virt_to_page(pbuf);
6888393c 2490 if (!page) {
c7506658
TW
2491 SAM("ERROR: page is NULL\n");
2492 return retcode;
2493 }
2494 get_page(page);
702422bd 2495/*---------------------------------------------------------------------------*/
6888393c 2496 if (!page) {
c7506658
TW
2497 SAM("ERROR: page is NULL after get_page(page)\n");
2498 } else {
2499 pvmf->page = page;
2500 retcode = VM_FAULT_MINOR;
2501 }
2502 return retcode;
702422bd 2503}
d090bf57
TW
2504
2505static const struct vm_operations_struct easycap_vm_ops = {
2506 .open = easycap_vma_open,
2507 .close = easycap_vma_close,
2508 .fault = easycap_vma_fault,
2509};
2510
2511static int easycap_mmap(struct file *file, struct vm_area_struct *pvma)
2512{
2513 JOT(8, "\n");
2514
2515 pvma->vm_ops = &easycap_vm_ops;
2516 pvma->vm_flags |= VM_RESERVED;
6888393c 2517 if (file)
d090bf57
TW
2518 pvma->vm_private_data = file->private_data;
2519 easycap_vma_open(pvma);
2520 return 0;
2521}
702422bd
T
2522/*****************************************************************************/
2523/*---------------------------------------------------------------------------*/
2524/*
2525 * ON COMPLETION OF A VIDEO URB ITS DATA IS COPIED TO THE FIELD BUFFERS
ce36ceda 2526 * PROVIDED peasycap->video_idle IS ZERO. REGARDLESS OF THIS BEING TRUE,
702422bd
T
2527 * IT IS RESUBMITTED PROVIDED peasycap->video_isoc_streaming IS NOT ZERO.
2528 *
2529 * THIS FUNCTION IS AN INTERRUPT SERVICE ROUTINE AND MUST NOT SLEEP.
2530 *
2531 * INFORMATION ABOUT THE VALIDITY OF THE CONTENTS OF THE FIELD BUFFER ARE
2532 * STORED IN THE TWO-BYTE STATUS PARAMETER
2533 * peasycap->field_buffer[peasycap->field_fill][0].kount
2534 * NOTICE THAT THE INFORMATION IS STORED ONLY WITH PAGE 0 OF THE FIELD BUFFER.
2535 *
2536 * THE LOWER BYTE CONTAINS THE FIELD PARITY BYTE FURNISHED BY THE SAA7113H
2537 * CHIP.
2538 *
2539 * THE UPPER BYTE IS ZERO IF NO PROBLEMS, OTHERWISE:
2540 * 0 != (kount & 0x8000) => AT LEAST ONE URB COMPLETED WITH ERRORS
2541 * 0 != (kount & 0x4000) => BUFFER HAS TOO MUCH DATA
2542 * 0 != (kount & 0x2000) => BUFFER HAS NOT ENOUGH DATA
f36bc37a 2543 * 0 != (kount & 0x1000) => BUFFER HAS DATA FROM DISPARATE INPUTS
ce36ceda 2544 * 0 != (kount & 0x0400) => RESERVED
702422bd
T
2545 * 0 != (kount & 0x0200) => FIELD BUFFER NOT YET CHECKED
2546 * 0 != (kount & 0x0100) => BUFFER HAS TWO EXTRA BYTES - WHY?
2547 */
2548/*---------------------------------------------------------------------------*/
d090bf57 2549static void easycap_complete(struct urb *purb)
702422bd 2550{
c7506658
TW
2551 struct easycap *peasycap;
2552 struct data_buffer *pfield_buffer;
2553 char errbuf[16];
2554 int i, more, much, leap, rc, last;
2555 int videofieldamount;
2556 unsigned int override, bad;
2557 int framestatus, framelength, frameactual, frameoffset;
2558 u8 *pu;
2559
6888393c 2560 if (!purb) {
c7506658
TW
2561 SAY("ERROR: easycap_complete(): purb is NULL\n");
2562 return;
2563 }
2564 peasycap = purb->context;
6888393c 2565 if (!peasycap) {
c7506658
TW
2566 SAY("ERROR: easycap_complete(): peasycap is NULL\n");
2567 return;
2568 }
c7506658
TW
2569 if (peasycap->video_eof)
2570 return;
2571 for (i = 0; i < VIDEO_ISOC_BUFFER_MANY; i++)
2572 if (purb->transfer_buffer == peasycap->video_isoc_buffer[i].pgo)
2573 break;
2574 JOM(16, "%2i=urb\n", i);
2575 last = peasycap->video_isoc_sequence;
2576 if ((((VIDEO_ISOC_BUFFER_MANY - 1) == last) && (0 != i)) ||
2577 (((VIDEO_ISOC_BUFFER_MANY - 1) != last) && ((last + 1) != i))) {
2578 JOM(16, "ERROR: out-of-order urbs %i,%i ... continuing\n",
2579 last, i);
2580 }
2581 peasycap->video_isoc_sequence = i;
702422bd 2582
c7506658
TW
2583 if (peasycap->video_idle) {
2584 JOM(16, "%i=video_idle %i=video_isoc_streaming\n",
2585 peasycap->video_idle, peasycap->video_isoc_streaming);
2586 if (peasycap->video_isoc_streaming) {
2587 rc = usb_submit_urb(purb, GFP_ATOMIC);
2588 if (rc) {
2589 SAM("%s:%d ENOMEM\n", strerror(rc), rc);
2590 if (-ENODEV != rc)
2591 SAM("ERROR: while %i=video_idle, "
2592 "usb_submit_urb() "
2593 "failed with rc:\n",
2594 peasycap->video_idle);
2595 }
702422bd 2596 }
c7506658 2597 return;
702422bd 2598 }
c7506658 2599 override = 0;
702422bd 2600/*---------------------------------------------------------------------------*/
c7506658
TW
2601 if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
2602 SAM("ERROR: bad peasycap->field_fill\n");
702422bd
T
2603 return;
2604 }
c7506658
TW
2605 if (purb->status) {
2606 if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
2607 JOM(8, "urb status -ESHUTDOWN or -ENOENT\n");
2608 return;
2609 }
702422bd 2610
c7506658
TW
2611 (peasycap->field_buffer[peasycap->field_fill][0].kount) |= 0x8000 ;
2612 SAM("ERROR: bad urb status -%s: %d\n",
2613 strerror(purb->status), purb->status);
702422bd 2614/*---------------------------------------------------------------------------*/
c7506658
TW
2615 } else {
2616 for (i = 0; i < purb->number_of_packets; i++) {
2617 if (0 != purb->iso_frame_desc[i].status) {
2618 (peasycap->field_buffer
2619 [peasycap->field_fill][0].kount) |= 0x8000 ;
2620 /* FIXME: 1. missing '-' check boundaries */
2621 strcpy(&errbuf[0],
2622 strerror(purb->iso_frame_desc[i].status));
702422bd 2623 }
c7506658
TW
2624 framestatus = purb->iso_frame_desc[i].status;
2625 framelength = purb->iso_frame_desc[i].length;
2626 frameactual = purb->iso_frame_desc[i].actual_length;
2627 frameoffset = purb->iso_frame_desc[i].offset;
2628
2629 JOM(16, "frame[%2i]:"
2630 "%4i=status "
2631 "%4i=actual "
2632 "%4i=length "
2633 "%5i=offset\n",
2634 i, framestatus, frameactual, framelength, frameoffset);
2635 if (!purb->iso_frame_desc[i].status) {
2636 more = purb->iso_frame_desc[i].actual_length;
2637 pfield_buffer = &peasycap->field_buffer
2638 [peasycap->field_fill][peasycap->field_page];
2639 videofieldamount = (peasycap->field_page *
2640 PAGE_SIZE) +
2641 (int)(pfield_buffer->pto - pfield_buffer->pgo);
2642 if (4 == more)
2643 peasycap->video_mt++;
2644 if (4 < more) {
2645 if (peasycap->video_mt) {
2646 JOM(8, "%4i empty video urb frames\n",
2647 peasycap->video_mt);
2648 peasycap->video_mt = 0;
2649 }
2650 if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
2651 SAM("ERROR: bad peasycap->field_fill\n");
2652 return;
2653 }
2654 if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
2655 peasycap->field_page) {
2656 SAM("ERROR: bad peasycap->field_page\n");
2657 return;
2658 }
2659 pfield_buffer = &peasycap->field_buffer
2660 [peasycap->field_fill][peasycap->field_page];
2661 pu = (u8 *)(purb->transfer_buffer +
2662 purb->iso_frame_desc[i].offset);
2663 if (0x80 & *pu)
2664 leap = 8;
2665 else
2666 leap = 4;
702422bd
T
2667/*--------------------------------------------------------------------------*/
2668/*
2669 * EIGHT-BYTE END-OF-VIDEOFIELD MARKER.
2670 * NOTE: A SUCCESSION OF URB FRAMES FOLLOWING THIS ARE EMPTY,
2671 * CORRESPONDING TO THE FIELD FLYBACK (VERTICAL BLANKING) PERIOD.
2672 *
2673 * PROVIDED THE FIELD BUFFER CONTAINS GOOD DATA AS INDICATED BY A ZERO UPPER
2674 * BYTE OF
2675 * peasycap->field_buffer[peasycap->field_fill][0].kount
2676 * THE CONTENTS OF THE FIELD BUFFER ARE OFFERED TO dqbuf(), field_read IS
2677 * UPDATED AND field_fill IS BUMPED. IF THE FIELD BUFFER CONTAINS BAD DATA
2678 * NOTHING IS OFFERED TO dqbuf().
2679 *
2680 * THE DECISION ON WHETHER THE PARITY OF THE OFFERED FIELD BUFFER IS RIGHT
2681 * RESTS WITH dqbuf().
2682 */
2683/*---------------------------------------------------------------------------*/
c7506658
TW
2684 if ((8 == more) || override) {
2685 if (videofieldamount >
2686 peasycap->videofieldamount) {
2687 if (2 == videofieldamount -
2688 peasycap->
2689 videofieldamount) {
2690 (peasycap->field_buffer
2691 [peasycap->field_fill]
2692 [0].kount) |= 0x0100;
2693 peasycap->video_junk += (1 +
2694 VIDEO_JUNK_TOLERATE);
2695 } else
2696 (peasycap->field_buffer
2697 [peasycap->field_fill]
2698 [0].kount) |= 0x4000;
2699 } else if (videofieldamount <
2700 peasycap->
2701 videofieldamount) {
2702 (peasycap->field_buffer
2703 [peasycap->field_fill]
2704 [0].kount) |= 0x2000;
2705 }
2706 bad = 0xFF00 & peasycap->field_buffer
2707 [peasycap->field_fill]
2708 [0].kount;
2709 if (!bad) {
2710 (peasycap->video_junk)--;
2711 if (-VIDEO_JUNK_TOLERATE >
2712 peasycap->video_junk)
2713 peasycap->video_junk =
2714 -VIDEO_JUNK_TOLERATE;
2715 peasycap->field_read =
2716 (peasycap->
2717 field_fill)++;
2718 if (FIELD_BUFFER_MANY <=
2719 peasycap->
2720 field_fill)
1dc6e418 2721 peasycap->
c7506658
TW
2722 field_fill = 0;
2723 peasycap->field_page = 0;
2724 pfield_buffer = &peasycap->
2725 field_buffer
2726 [peasycap->
2727 field_fill]
2728 [peasycap->
2729 field_page];
2730 pfield_buffer->pto =
2731 pfield_buffer->pgo;
2732 JOM(8, "bumped to: %i="
2733 "peasycap->"
2734 "field_fill %i="
2735 "parity\n",
2736 peasycap->field_fill,
2737 0x00FF &
2738 pfield_buffer->kount);
2739 JOM(8, "field buffer %i has "
2740 "%i bytes fit to be "
2741 "read\n",
2742 peasycap->field_read,
2743 videofieldamount);
2744 JOM(8, "wakeup call to "
2745 "wq_video, "
2746 "%i=field_read "
2747 "%i=field_fill "
2748 "%i=parity\n",
2749 peasycap->field_read,
2750 peasycap->field_fill,
2751 0x00FF & peasycap->
2752 field_buffer
2753 [peasycap->
2754 field_read][0].kount);
2755 wake_up_interruptible
2756 (&(peasycap->
2757 wq_video));
2758 do_gettimeofday
2759 (&peasycap->timeval7);
2760 } else {
2761 peasycap->video_junk++;
2762 if (bad & 0x0010)
2763 peasycap->video_junk +=
2764 (1 + VIDEO_JUNK_TOLERATE/2);
2765 JOM(8, "field buffer %i had %i "
2766 "bytes, now discarded: "
2767 "0x%04X\n",
2768 peasycap->field_fill,
2769 videofieldamount,
2770 (0xFF00 &
2771 peasycap->field_buffer
2772 [peasycap->field_fill][0].
2773 kount));
2774 (peasycap->field_fill)++;
2775
2776 if (FIELD_BUFFER_MANY <=
2777 peasycap->field_fill)
2778 peasycap->field_fill = 0;
f36bc37a 2779 peasycap->field_page = 0;
c7506658
TW
2780 pfield_buffer =
2781 &peasycap->field_buffer
2782 [peasycap->field_fill]
2783 [peasycap->field_page];
1dc6e418 2784 pfield_buffer->pto =
c7506658
TW
2785 pfield_buffer->pgo;
2786
2787 JOM(8, "bumped to: %i=peasycap->"
2788 "field_fill %i=parity\n",
1dc6e418 2789 peasycap->field_fill,
c7506658
TW
2790 0x00FF & pfield_buffer->kount);
2791 }
2792 if (8 == more) {
2793 JOM(8, "end-of-field: received "
2794 "parity byte 0x%02X\n",
2795 (0xFF & *pu));
2796 if (0x40 & *pu)
2797 pfield_buffer->kount = 0x0000;
2798 else
2799 pfield_buffer->kount = 0x0001;
2800 pfield_buffer->input = 0x08 |
2801 (0x07 & peasycap->input);
2802 JOM(8, "end-of-field: 0x%02X=kount\n",
2803 0xFF & pfield_buffer->kount);
2804 }
702422bd 2805 }
702422bd
T
2806/*---------------------------------------------------------------------------*/
2807/*
2808 * COPY more BYTES FROM ISOC BUFFER TO FIELD BUFFER
2809 */
2810/*---------------------------------------------------------------------------*/
c7506658
TW
2811 pu += leap;
2812 more -= leap;
702422bd 2813
c7506658
TW
2814 if (FIELD_BUFFER_MANY <= peasycap->field_fill) {
2815 SAM("ERROR: bad peasycap->field_fill\n");
702422bd
T
2816 return;
2817 }
c7506658
TW
2818 if (FIELD_BUFFER_SIZE/PAGE_SIZE <= peasycap->field_page) {
2819 SAM("ERROR: bad peasycap->field_page\n");
2820 return;
2821 }
2822 pfield_buffer = &peasycap->field_buffer
2823 [peasycap->field_fill][peasycap->field_page];
2824 while (more) {
2825 pfield_buffer = &peasycap->field_buffer
1dc6e418 2826 [peasycap->field_fill]
702422bd 2827 [peasycap->field_page];
c7506658
TW
2828 if (PAGE_SIZE < (pfield_buffer->pto -
2829 pfield_buffer->pgo)) {
2830 SAM("ERROR: bad pfield_buffer->pto\n");
2831 return;
2832 }
2833 if (PAGE_SIZE == (pfield_buffer->pto -
2834 pfield_buffer->pgo)) {
2835 (peasycap->field_page)++;
2836 if (FIELD_BUFFER_SIZE/PAGE_SIZE <=
2837 peasycap->field_page) {
2838 JOM(16, "wrapping peasycap->"
2839 "field_page\n");
2840 peasycap->field_page = 0;
2841 }
2842 pfield_buffer = &peasycap->
2843 field_buffer
2844 [peasycap->field_fill]
2845 [peasycap->field_page];
2846 pfield_buffer->pto = pfield_buffer->pgo;
2847 pfield_buffer->input = 0x08 |
2848 (0x07 & peasycap->input);
2849 if ((peasycap->field_buffer[peasycap->
2850 field_fill][0]).
2851 input !=
2852 pfield_buffer->input)
2853 (peasycap->field_buffer
2854 [peasycap->field_fill]
2855 [0]).kount |= 0x1000;
2856 }
702422bd 2857
c7506658
TW
2858 much = PAGE_SIZE -
2859 (int)(pfield_buffer->pto -
702422bd
T
2860 pfield_buffer->pgo);
2861
c7506658
TW
2862 if (much > more)
2863 much = more;
2864 memcpy(pfield_buffer->pto, pu, much);
2865 pu += much;
2866 (pfield_buffer->pto) += much;
2867 more -= much;
2868 }
702422bd
T
2869 }
2870 }
2871 }
2872 }
702422bd 2873/*---------------------------------------------------------------------------*/
702422bd
T
2874/*
2875 * RESUBMIT THIS URB, UNLESS A SEVERE PERSISTENT ERROR CONDITION EXISTS.
2876 *
2877 * IF THE WAIT QUEUES ARE NOT CLEARED IN RESPONSE TO AN ERROR CONDITION
2878 * THE USERSPACE PROGRAM, E.G. mplayer, MAY HANG ON EXIT. BEWARE.
2879 */
2880/*---------------------------------------------------------------------------*/
c7506658
TW
2881 if (VIDEO_ISOC_BUFFER_MANY <= peasycap->video_junk) {
2882 SAM("easycap driver shutting down on condition green\n");
2883 peasycap->status = 1;
2884 peasycap->video_eof = 1;
2885 peasycap->video_junk = 0;
2886 wake_up_interruptible(&peasycap->wq_video);
f36bc37a 2887#if !defined(PERSEVERE)
c7506658
TW
2888 peasycap->audio_eof = 1;
2889 wake_up_interruptible(&peasycap->wq_audio);
f36bc37a 2890#endif /*PERSEVERE*/
c7506658 2891 return;
702422bd 2892 }
c7506658
TW
2893 if (peasycap->video_isoc_streaming) {
2894 rc = usb_submit_urb(purb, GFP_ATOMIC);
2895 if (rc) {
2896 SAM("%s: %d\n", strerror(rc), rc);
2897 if (-ENODEV != rc)
2898 SAM("ERROR: while %i=video_idle, "
2899 "usb_submit_urb() "
2900 "failed with rc:\n",
2901 peasycap->video_idle);
2902 }
2903 }
2904 return;
702422bd 2905}
d090bf57
TW
2906static const struct file_operations easycap_fops = {
2907 .owner = THIS_MODULE,
2908 .open = easycap_open,
f2b3c685 2909 .unlocked_ioctl = easycap_unlocked_ioctl,
d090bf57
TW
2910 .poll = easycap_poll,
2911 .mmap = easycap_mmap,
2912 .llseek = no_llseek,
2913};
2914static const struct usb_class_driver easycap_class = {
2915 .name = "usb/easycap%d",
2916 .fops = &easycap_fops,
2917 .minor_base = USB_SKEL_MINOR_BASE,
2918};
2919/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
d090bf57
TW
2920static const struct v4l2_file_operations v4l2_fops = {
2921 .owner = THIS_MODULE,
2922 .open = easycap_open_noinode,
f2b3c685 2923 .unlocked_ioctl = easycap_unlocked_ioctl,
d090bf57
TW
2924 .poll = easycap_poll,
2925 .mmap = easycap_mmap,
2926};
702422bd
T
2927/*****************************************************************************/
2928/*---------------------------------------------------------------------------*/
2929/*
a9855917
MT
2930 * WHEN THE EasyCAP IS PHYSICALLY PLUGGED IN, THIS FUNCTION IS CALLED THREE
2931 * TIMES, ONCE FOR EACH OF THE THREE INTERFACES. BEWARE.
702422bd
T
2932 */
2933/*---------------------------------------------------------------------------*/
11ff12fe
TW
2934static int easycap_usb_probe(struct usb_interface *intf,
2935 const struct usb_device_id *id)
702422bd 2936{
11ff12fe
TW
2937 struct usb_device *usbdev;
2938 struct usb_host_interface *alt;
2939 struct usb_endpoint_descriptor *ep;
2940 struct usb_interface_descriptor *interface;
7dcef374
TW
2941 struct urb *purb;
2942 struct easycap *peasycap;
2943 int ndong;
2944 struct data_urb *pdata_urb;
1d243c2e 2945 int i, j, k, m, rc;
7dcef374
TW
2946 u8 bInterfaceNumber;
2947 u8 bInterfaceClass;
2948 u8 bInterfaceSubClass;
2949 void *pbuf;
2950 int okalt[8], isokalt;
2951 int okepn[8];
2952 int okmps[8];
2953 int maxpacketsize;
2954 u16 mask;
2955 s32 value;
2956 struct easycap_format *peasycap_format;
b4a5916e
TW
2957 int fmtidx;
2958 struct inputset *inputset;
702422bd 2959
11ff12fe 2960 usbdev = interface_to_usbdev(intf);
ee99aa49 2961
702422bd 2962/*---------------------------------------------------------------------------*/
11ff12fe
TW
2963 alt = usb_altnum_to_altsetting(intf, 0);
2964 if (!alt) {
2965 SAY("ERROR: usb_host_interface not found\n");
7dcef374
TW
2966 return -EFAULT;
2967 }
11ff12fe
TW
2968 interface = &alt->desc;
2969 if (!interface) {
2970 SAY("ERROR: intf_descriptor is NULL\n");
7dcef374
TW
2971 return -EFAULT;
2972 }
702422bd
T
2973/*---------------------------------------------------------------------------*/
2974/*
2975 * GET PROPERTIES OF PROBED INTERFACE
2976 */
2977/*---------------------------------------------------------------------------*/
11ff12fe
TW
2978 bInterfaceNumber = interface->bInterfaceNumber;
2979 bInterfaceClass = interface->bInterfaceClass;
2980 bInterfaceSubClass = interface->bInterfaceSubClass;
7dcef374 2981
e03da5e2 2982 JOT(4, "intf[%i]: num_altsetting=%i\n",
11ff12fe 2983 bInterfaceNumber, intf->num_altsetting);
e03da5e2
TW
2984 JOT(4, "intf[%i]: cur_altsetting - altsetting=%li\n",
2985 bInterfaceNumber,
11ff12fe 2986 (long int)(intf->cur_altsetting - intf->altsetting));
e03da5e2
TW
2987 JOT(4, "intf[%i]: bInterfaceClass=0x%02X bInterfaceSubClass=0x%02X\n",
2988 bInterfaceNumber, bInterfaceClass, bInterfaceSubClass);
702422bd
T
2989/*---------------------------------------------------------------------------*/
2990/*
2991 * A NEW struct easycap IS ALWAYS ALLOCATED WHEN INTERFACE 0 IS PROBED.
2992 * IT IS NOT POSSIBLE HERE TO FREE ANY EXISTING struct easycap. THIS
e68703cf
MT
2993 * SHOULD HAVE BEEN DONE BY easycap_delete() WHEN THE EasyCAP WAS
2994 * PHYSICALLY UNPLUGGED.
2995 *
2996 * THE POINTER peasycap TO THE struct easycap IS REMEMBERED WHEN
2997 * INTERFACES 1 AND 2 ARE PROBED.
e68703cf 2998*/
702422bd 2999/*---------------------------------------------------------------------------*/
7dcef374
TW
3000 if (0 == bInterfaceNumber) {
3001 peasycap = kzalloc(sizeof(struct easycap), GFP_KERNEL);
6888393c 3002 if (!peasycap) {
7dcef374
TW
3003 SAY("ERROR: Could not allocate peasycap\n");
3004 return -ENOMEM;
3005 }
702422bd
T
3006/*---------------------------------------------------------------------------*/
3007/*
e68703cf
MT
3008 * PERFORM URGENT INTIALIZATIONS ...
3009*/
702422bd 3010/*---------------------------------------------------------------------------*/
7dcef374 3011 peasycap->minor = -1;
7dcef374
TW
3012 kref_init(&peasycap->kref);
3013 JOM(8, "intf[%i]: after kref_init(..._video) "
3014 "%i=peasycap->kref.refcount.counter\n",
3015 bInterfaceNumber, peasycap->kref.refcount.counter);
702422bd 3016
7dcef374
TW
3017 /* module params */
3018 peasycap->gain = (s8)clamp(easycap_gain, 0, 31);
2a9a05c4 3019
7dcef374
TW
3020 init_waitqueue_head(&peasycap->wq_video);
3021 init_waitqueue_head(&peasycap->wq_audio);
3022 init_waitqueue_head(&peasycap->wq_trigger);
e68703cf 3023
7dcef374 3024 if (mutex_lock_interruptible(&mutex_dongle)) {
dfcce7bf 3025 SAY("ERROR: cannot down mutex_dongle\n");
7dcef374
TW
3026 return -ERESTARTSYS;
3027 } else {
a9855917
MT
3028/*---------------------------------------------------------------------------*/
3029 /*
3030 * FOR INTERFACES 1 AND 2 THE POINTER peasycap WILL NEED TO
3031 * TO BE THE SAME AS THAT ALLOCATED NOW FOR INTERFACE 0.
3032 *
3033 * NORMALLY ndong WILL NOT HAVE CHANGED SINCE INTERFACE 0 WAS
3034 * PROBED, BUT THIS MAY NOT BE THE CASE IF, FOR EXAMPLE, TWO
3035 * EASYCAPs ARE PLUGGED IN SIMULTANEOUSLY.
3036 */
3037/*---------------------------------------------------------------------------*/
7dcef374 3038 for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
6888393c 3039 if ((!easycapdc60_dongle[ndong].peasycap) &&
7dcef374
TW
3040 (!mutex_is_locked(&easycapdc60_dongle
3041 [ndong].mutex_video)) &&
3042 (!mutex_is_locked(&easycapdc60_dongle
3043 [ndong].mutex_audio))) {
3044 easycapdc60_dongle[ndong].peasycap = peasycap;
3045 peasycap->isdongle = ndong;
3046 JOM(8, "intf[%i]: peasycap-->easycap"
3047 "_dongle[%i].peasycap\n",
3048 bInterfaceNumber, ndong);
3049 break;
3050 }
3051 }
3052 if (DONGLE_MANY <= ndong) {
3053 SAM("ERROR: too many dongles\n");
3054 mutex_unlock(&mutex_dongle);
3055 return -ENOMEM;
ae59dad4 3056 }
a9855917 3057 mutex_unlock(&mutex_dongle);
a9855917 3058 }
7dcef374
TW
3059 peasycap->allocation_video_struct = sizeof(struct easycap);
3060 peasycap->allocation_video_page = 0;
3061 peasycap->allocation_video_urb = 0;
3062 peasycap->allocation_audio_struct = 0;
3063 peasycap->allocation_audio_page = 0;
3064 peasycap->allocation_audio_urb = 0;
e68703cf
MT
3065
3066/*---------------------------------------------------------------------------*/
3067/*
3068 * ... AND FURTHER INITIALIZE THE STRUCTURE
3069*/
3070/*---------------------------------------------------------------------------*/
11ff12fe
TW
3071 peasycap->pusb_device = usbdev;
3072 peasycap->pusb_interface = intf;
702422bd 3073
7dcef374
TW
3074 peasycap->ilk = 0;
3075 peasycap->microphone = false;
702422bd 3076
7dcef374
TW
3077 peasycap->video_interface = -1;
3078 peasycap->video_altsetting_on = -1;
3079 peasycap->video_altsetting_off = -1;
3080 peasycap->video_endpointnumber = -1;
3081 peasycap->video_isoc_maxframesize = -1;
3082 peasycap->video_isoc_buffer_size = -1;
702422bd 3083
7dcef374
TW
3084 peasycap->audio_interface = -1;
3085 peasycap->audio_altsetting_on = -1;
3086 peasycap->audio_altsetting_off = -1;
3087 peasycap->audio_endpointnumber = -1;
3088 peasycap->audio_isoc_maxframesize = -1;
3089 peasycap->audio_isoc_buffer_size = -1;
702422bd 3090
7dcef374 3091 peasycap->frame_buffer_many = FRAME_BUFFER_MANY;
e68703cf 3092
7dcef374
TW
3093 for (k = 0; k < INPUT_MANY; k++)
3094 peasycap->lost[k] = 0;
3095 peasycap->skip = 0;
3096 peasycap->skipped = 0;
3097 peasycap->offerfields = 0;
702422bd
T
3098/*---------------------------------------------------------------------------*/
3099/*
f36bc37a 3100 * DYNAMICALLY FILL IN THE AVAILABLE FORMATS ...
702422bd
T
3101 */
3102/*---------------------------------------------------------------------------*/
7dcef374
TW
3103 rc = fillin_formats();
3104 if (0 > rc) {
c7506658 3105 SAM("ERROR: fillin_formats() rc = %i\n", rc);
7dcef374
TW
3106 return -EFAULT;
3107 }
3108 JOM(4, "%i formats available\n", rc);
f36bc37a
MT
3109/*---------------------------------------------------------------------------*/
3110/*
3111 * ... AND POPULATE easycap.inputset[]
3112*/
3113/*---------------------------------------------------------------------------*/
b4a5916e
TW
3114 /* FIXME: maybe we just use memset 0 */
3115 inputset = peasycap->inputset;
7dcef374 3116 for (k = 0; k < INPUT_MANY; k++) {
b4a5916e
TW
3117 inputset[k].input_ok = 0;
3118 inputset[k].standard_offset_ok = 0;
3119 inputset[k].format_offset_ok = 0;
3120 inputset[k].brightness_ok = 0;
3121 inputset[k].contrast_ok = 0;
3122 inputset[k].saturation_ok = 0;
3123 inputset[k].hue_ok = 0;
7dcef374 3124 }
b4a5916e
TW
3125
3126 fmtidx = peasycap->ntsc ? NTSC_M : PAL_BGHIN;
3127 m = 0;
3128 mask = 0;
3129 for (i = 0; 0xFFFF != easycap_standard[i].mask; i++) {
3130 if (fmtidx == easycap_standard[i].v4l2_standard.index) {
3131 m++;
3132 for (k = 0; k < INPUT_MANY; k++)
3133 inputset[k].standard_offset = i;
3134
7dcef374 3135 mask = easycap_standard[i].mask;
f36bc37a 3136 }
f36bc37a 3137 }
7dcef374
TW
3138
3139 if (1 != m) {
b4a5916e
TW
3140 SAM("ERROR: "
3141 "inputset->standard_offset unpopulated, %i=m\n", m);
7dcef374
TW
3142 return -ENOENT;
3143 }
3144
3145 peasycap_format = &easycap_format[0];
f36bc37a 3146 m = 0;
b4a5916e
TW
3147 for (i = 0; peasycap_format->v4l2_format.fmt.pix.width; i++) {
3148 struct v4l2_pix_format *pix =
3149 &peasycap_format->v4l2_format.fmt.pix;
7dcef374 3150 if (((peasycap_format->mask & 0x0F) == (mask & 0x0F)) &&
b4a5916e
TW
3151 pix->field == V4L2_FIELD_NONE &&
3152 pix->pixelformat == V4L2_PIX_FMT_UYVY &&
3153 pix->width == 640 && pix->height == 480) {
f36bc37a 3154 m++;
7dcef374 3155 for (k = 0; k < INPUT_MANY; k++)
b4a5916e 3156 inputset[k].format_offset = i;
7dcef374 3157 break;
f36bc37a 3158 }
e03da5e2 3159 peasycap_format++;
f36bc37a 3160 }
7dcef374 3161 if (1 != m) {
b4a5916e 3162 SAM("ERROR: inputset[]->format_offset unpopulated\n");
e03da5e2 3163 return -ENOENT;
f36bc37a 3164 }
f36bc37a 3165
7dcef374 3166 m = 0;
b4a5916e 3167 for (i = 0; 0xFFFFFFFF != easycap_control[i].id; i++) {
7dcef374
TW
3168 value = easycap_control[i].default_value;
3169 if (V4L2_CID_BRIGHTNESS == easycap_control[i].id) {
3170 m++;
3171 for (k = 0; k < INPUT_MANY; k++)
b4a5916e 3172 inputset[k].brightness = value;
7dcef374
TW
3173 } else if (V4L2_CID_CONTRAST == easycap_control[i].id) {
3174 m++;
3175 for (k = 0; k < INPUT_MANY; k++)
b4a5916e 3176 inputset[k].contrast = value;
7dcef374
TW
3177 } else if (V4L2_CID_SATURATION == easycap_control[i].id) {
3178 m++;
3179 for (k = 0; k < INPUT_MANY; k++)
b4a5916e 3180 inputset[k].saturation = value;
7dcef374
TW
3181 } else if (V4L2_CID_HUE == easycap_control[i].id) {
3182 m++;
3183 for (k = 0; k < INPUT_MANY; k++)
b4a5916e 3184 inputset[k].hue = value;
7dcef374 3185 }
f36bc37a 3186 }
e03da5e2 3187
7dcef374 3188 if (4 != m) {
b4a5916e 3189 SAM("ERROR: inputset[]->brightness underpopulated\n");
7dcef374
TW
3190 return -ENOENT;
3191 }
3192 for (k = 0; k < INPUT_MANY; k++)
b4a5916e
TW
3193 inputset[k].input = k;
3194 JOM(4, "populated inputset[]\n");
7dcef374
TW
3195 JOM(4, "finished initialization\n");
3196 } else {
702422bd 3197/*---------------------------------------------------------------------------*/
a9855917
MT
3198/*
3199 * FIXME
3200 *
3201 * IDENTIFY THE APPROPRIATE POINTER peasycap FOR INTERFACES 1 AND 2.
3202 * THE ADDRESS OF peasycap->pusb_device IS RELUCTANTLY USED FOR THIS PURPOSE.
3203 */
e68703cf 3204/*---------------------------------------------------------------------------*/
7dcef374 3205 for (ndong = 0; ndong < DONGLE_MANY; ndong++) {
11ff12fe 3206 if (usbdev == easycapdc60_dongle[ndong].peasycap->
7dcef374
TW
3207 pusb_device) {
3208 peasycap = easycapdc60_dongle[ndong].peasycap;
c7506658
TW
3209 JOT(8, "intf[%i]: dongle[%i].peasycap\n",
3210 bInterfaceNumber, ndong);
7dcef374
TW
3211 break;
3212 }
3213 }
3214 if (DONGLE_MANY <= ndong) {
3215 SAY("ERROR: peasycap is unknown when probing interface %i\n",
3216 bInterfaceNumber);
3217 return -ENODEV;
3218 }
6888393c 3219 if (!peasycap) {
7dcef374
TW
3220 SAY("ERROR: peasycap is NULL when probing interface %i\n",
3221 bInterfaceNumber);
3222 return -ENODEV;
a9855917 3223 }
dfcce7bf 3224 }
702422bd 3225/*---------------------------------------------------------------------------*/
7dcef374 3226 if ((USB_CLASS_VIDEO == bInterfaceClass) ||
dfcce7bf 3227 (USB_CLASS_VENDOR_SPEC == bInterfaceClass)) {
7dcef374
TW
3228 if (-1 == peasycap->video_interface) {
3229 peasycap->video_interface = bInterfaceNumber;
3230 JOM(4, "setting peasycap->video_interface=%i\n",
3231 peasycap->video_interface);
3232 } else {
3233 if (peasycap->video_interface != bInterfaceNumber) {
3234 SAM("ERROR: attempting to reset "
3235 "peasycap->video_interface\n");
3236 SAM("...... continuing with "
3237 "%i=peasycap->video_interface\n",
702422bd 3238 peasycap->video_interface);
7dcef374 3239 }
702422bd 3240 }
7dcef374 3241 } else if ((USB_CLASS_AUDIO == bInterfaceClass) &&
fc3cc2ca 3242 (USB_SUBCLASS_AUDIOSTREAMING == bInterfaceSubClass)) {
7dcef374
TW
3243 if (-1 == peasycap->audio_interface) {
3244 peasycap->audio_interface = bInterfaceNumber;
3245 JOM(4, "setting peasycap->audio_interface=%i\n",
3246 peasycap->audio_interface);
3247 } else {
3248 if (peasycap->audio_interface != bInterfaceNumber) {
3249 SAM("ERROR: attempting to reset "
3250 "peasycap->audio_interface\n");
3251 SAM("...... continuing with "
3252 "%i=peasycap->audio_interface\n",
3253 peasycap->audio_interface);
3254 }
702422bd
T
3255 }
3256 }
702422bd
T
3257/*---------------------------------------------------------------------------*/
3258/*
3259 * INVESTIGATE ALL ALTSETTINGS.
3260 * DONE IN DETAIL BECAUSE USB DEVICE 05e1:0408 HAS DISPARATE INCARNATIONS.
3261 */
3262/*---------------------------------------------------------------------------*/
7dcef374 3263 isokalt = 0;
702422bd 3264
11ff12fe
TW
3265 for (i = 0; i < intf->num_altsetting; i++) {
3266 alt = usb_altnum_to_altsetting(intf, i);
3267 if (!alt) {
3268 SAM("ERROR: alt is NULL\n");
7dcef374 3269 return -EFAULT;
702422bd 3270 }
11ff12fe
TW
3271 interface = &alt->desc;
3272 if (!interface) {
3273 SAM("ERROR: intf_descriptor is NULL\n");
7dcef374 3274 return -EFAULT;
702422bd 3275 }
7dcef374 3276
11ff12fe 3277 if (0 == interface->bNumEndpoints)
e03da5e2
TW
3278 JOM(4, "intf[%i]alt[%i] has no endpoints\n",
3279 bInterfaceNumber, i);
7dcef374 3280/*---------------------------------------------------------------------------*/
11ff12fe
TW
3281 for (j = 0; j < interface->bNumEndpoints; j++) {
3282 ep = &alt->endpoint[j].desc;
3283 if (!ep) {
3284 SAM("ERROR: ep is NULL.\n");
7dcef374
TW
3285 SAM("...... skipping\n");
3286 continue;
3287 }
1d243c2e
TW
3288
3289 if (!usb_endpoint_is_isoc_in(ep)) {
3290 JOM(4, "intf[%i]alt[%i]end[%i] is a %d endpoint\n",
3291 bInterfaceNumber,
3292 i, j, ep->bmAttributes);
3293 if (usb_endpoint_dir_out(ep)) {
3294 SAM("ERROR: OUT endpoint unexpected\n");
3295 SAM("...... continuing\n");
3296 }
3297 continue;
7dcef374 3298 }
1d243c2e
TW
3299 switch (bInterfaceClass) {
3300 case USB_CLASS_VIDEO:
3301 case USB_CLASS_VENDOR_SPEC: {
3302 if (ep->wMaxPacketSize) {
3303 if (8 > isokalt) {
3304 okalt[isokalt] = i;
3305 JOM(4,
3306 "%i=okalt[%i]\n",
3307 okalt[isokalt],
3308 isokalt);
3309 okepn[isokalt] =
3310 ep->
3311 bEndpointAddress &
3312 0x0F;
3313 JOM(4,
3314 "%i=okepn[%i]\n",
3315 okepn[isokalt],
3316 isokalt);
3317 okmps[isokalt] =
3318 le16_to_cpu(ep->
3319 wMaxPacketSize);
3320 JOM(4,
3321 "%i=okmps[%i]\n",
3322 okmps[isokalt],
3323 isokalt);
3324 isokalt++;
702422bd 3325 }
1d243c2e
TW
3326 } else {
3327 if (-1 == peasycap->
3328 video_altsetting_off) {
3329 peasycap->
3330 video_altsetting_off =
3331 i;
3332 JOM(4, "%i=video_"
3333 "altsetting_off "
3334 "<====\n",
3335 peasycap->
3336 video_altsetting_off);
3337 } else {
3338 SAM("ERROR: peasycap"
3339 "->video_altsetting_"
3340 "off already set\n");
3341 SAM("...... "
3342 "continuing with "
3343 "%i=peasycap->video_"
3344 "altsetting_off\n",
3345 peasycap->
3346 video_altsetting_off);
3347 }
3348 }
3349 break;
3350 }
3351 case USB_CLASS_AUDIO: {
3352 if (bInterfaceSubClass !=
3353 USB_SUBCLASS_AUDIOSTREAMING)
702422bd 3354 break;
1d243c2e
TW
3355 if (!peasycap) {
3356 SAM("MISTAKE: "
3357 "peasycap is NULL\n");
3358 return -EFAULT;
3359 }
3360 if (ep->wMaxPacketSize) {
3361 if (8 > isokalt) {
3362 okalt[isokalt] = i ;
3363 JOM(4,
3364 "%i=okalt[%i]\n",
3365 okalt[isokalt],
3366 isokalt);
3367 okepn[isokalt] =
3368 ep->
3369 bEndpointAddress &
3370 0x0F;
3371 JOM(4,
3372 "%i=okepn[%i]\n",
3373 okepn[isokalt],
3374 isokalt);
3375 okmps[isokalt] =
3376 le16_to_cpu(ep->
3377 wMaxPacketSize);
3378 JOM(4,
3379 "%i=okmps[%i]\n",
3380 okmps[isokalt],
3381 isokalt);
3382 isokalt++;
7dcef374 3383 }
1d243c2e
TW
3384 } else {
3385 if (-1 == peasycap->
3386 audio_altsetting_off) {
3387 peasycap->
3388 audio_altsetting_off =
3389 i;
3390 JOM(4, "%i=audio_"
3391 "altsetting_off "
3392 "<====\n",
3393 peasycap->
3394 audio_altsetting_off);
3395 } else {
3396 SAM("ERROR: peasycap"
3397 "->audio_altsetting_"
3398 "off already set\n");
3399 SAM("...... "
3400 "continuing with "
3401 "%i=peasycap->"
3402 "audio_altsetting_"
3403 "off\n",
3404 peasycap->
3405 audio_altsetting_off);
7dcef374 3406 }
702422bd 3407 }
1d243c2e
TW
3408 break;
3409 }
3410 default:
3411 break;
7dcef374 3412 }
11ff12fe 3413 if (0 == ep->wMaxPacketSize) {
7dcef374
TW
3414 JOM(4, "intf[%i]alt[%i]end[%i] "
3415 "has zero packet size\n",
3416 bInterfaceNumber, i, j);
702422bd 3417 }
702422bd
T
3418 }
3419 }
702422bd
T
3420/*---------------------------------------------------------------------------*/
3421/*
3422 * PERFORM INITIALIZATION OF THE PROBED INTERFACE
3423 */
3424/*---------------------------------------------------------------------------*/
7dcef374 3425 JOM(4, "initialization begins for interface %i\n",
11ff12fe 3426 interface->bInterfaceNumber);
7dcef374 3427 switch (bInterfaceNumber) {
702422bd
T
3428/*---------------------------------------------------------------------------*/
3429/*
3430 * INTERFACE 0 IS THE VIDEO INTERFACE
3431 */
3432/*---------------------------------------------------------------------------*/
7dcef374
TW
3433 case 0: {
3434 if (!peasycap) {
3435 SAM("MISTAKE: peasycap is NULL\n");
3436 return -EFAULT;
3437 }
3438 if (!isokalt) {
3439 SAM("ERROR: no viable video_altsetting_on\n");
3440 return -ENOENT;
3441 } else {
3442 peasycap->video_altsetting_on = okalt[isokalt - 1];
3443 JOM(4, "%i=video_altsetting_on <====\n",
3444 peasycap->video_altsetting_on);
3445 }
702422bd
T
3446/*---------------------------------------------------------------------------*/
3447/*
3448 * DECIDE THE VIDEO STREAMING PARAMETERS
3449 */
3450/*---------------------------------------------------------------------------*/
7dcef374
TW
3451 peasycap->video_endpointnumber = okepn[isokalt - 1];
3452 JOM(4, "%i=video_endpointnumber\n", peasycap->video_endpointnumber);
3453 maxpacketsize = okmps[isokalt - 1];
e03da5e2
TW
3454
3455 peasycap->video_isoc_maxframesize =
3456 min(maxpacketsize, USB_2_0_MAXPACKETSIZE);
7dcef374
TW
3457 if (0 >= peasycap->video_isoc_maxframesize) {
3458 SAM("ERROR: bad video_isoc_maxframesize\n");
3459 SAM(" possibly because port is USB 1.1\n");
3460 return -ENOENT;
3461 }
e03da5e2
TW
3462 JOM(4, "%i=video_isoc_maxframesize\n",
3463 peasycap->video_isoc_maxframesize);
3464
7dcef374
TW
3465 peasycap->video_isoc_framesperdesc = VIDEO_ISOC_FRAMESPERDESC;
3466 JOM(4, "%i=video_isoc_framesperdesc\n",
3467 peasycap->video_isoc_framesperdesc);
3468 if (0 >= peasycap->video_isoc_framesperdesc) {
3469 SAM("ERROR: bad video_isoc_framesperdesc\n");
3470 return -ENOENT;
3471 }
3472 peasycap->video_isoc_buffer_size =
3473 peasycap->video_isoc_maxframesize *
3474 peasycap->video_isoc_framesperdesc;
3475 JOM(4, "%i=video_isoc_buffer_size\n",
3476 peasycap->video_isoc_buffer_size);
3477 if ((PAGE_SIZE << VIDEO_ISOC_ORDER) <
3478 peasycap->video_isoc_buffer_size) {
3479 SAM("MISTAKE: peasycap->video_isoc_buffer_size too big\n");
3480 return -EFAULT;
3481 }
702422bd 3482/*---------------------------------------------------------------------------*/
7dcef374
TW
3483 if (-1 == peasycap->video_interface) {
3484 SAM("MISTAKE: video_interface is unset\n");
3485 return -EFAULT;
3486 }
3487 if (-1 == peasycap->video_altsetting_on) {
3488 SAM("MISTAKE: video_altsetting_on is unset\n");
3489 return -EFAULT;
3490 }
3491 if (-1 == peasycap->video_altsetting_off) {
3492 SAM("MISTAKE: video_interface_off is unset\n");
3493 return -EFAULT;
3494 }
3495 if (-1 == peasycap->video_endpointnumber) {
3496 SAM("MISTAKE: video_endpointnumber is unset\n");
3497 return -EFAULT;
3498 }
3499 if (-1 == peasycap->video_isoc_maxframesize) {
3500 SAM("MISTAKE: video_isoc_maxframesize is unset\n");
3501 return -EFAULT;
3502 }
3503 if (-1 == peasycap->video_isoc_buffer_size) {
3504 SAM("MISTAKE: video_isoc_buffer_size is unset\n");
3505 return -EFAULT;
3506 }
702422bd
T
3507/*---------------------------------------------------------------------------*/
3508/*
3509 * ALLOCATE MEMORY FOR VIDEO BUFFERS. LISTS MUST BE INITIALIZED FIRST.
3510 */
3511/*---------------------------------------------------------------------------*/
7dcef374
TW
3512 INIT_LIST_HEAD(&(peasycap->urb_video_head));
3513 peasycap->purb_video_head = &(peasycap->urb_video_head);
3514/*---------------------------------------------------------------------------*/
3515 JOM(4, "allocating %i frame buffers of size %li\n",
3516 FRAME_BUFFER_MANY, (long int)FRAME_BUFFER_SIZE);
3517 JOM(4, ".... each scattered over %li pages\n",
3518 FRAME_BUFFER_SIZE/PAGE_SIZE);
3519
3520 for (k = 0; k < FRAME_BUFFER_MANY; k++) {
3521 for (m = 0; m < FRAME_BUFFER_SIZE/PAGE_SIZE; m++) {
6888393c 3522 if (peasycap->frame_buffer[k][m].pgo)
7dcef374
TW
3523 SAM("attempting to reallocate frame "
3524 " buffers\n");
3525 else {
3526 pbuf = (void *)__get_free_page(GFP_KERNEL);
6888393c 3527 if (!pbuf) {
7dcef374
TW
3528 SAM("ERROR: Could not allocate frame "
3529 "buffer %i page %i\n", k, m);
3530 return -ENOMEM;
3531 } else
3532 peasycap->allocation_video_page += 1;
3533 peasycap->frame_buffer[k][m].pgo = pbuf;
3534 }
3535 peasycap->frame_buffer[k][m].pto =
3536 peasycap->frame_buffer[k][m].pgo;
702422bd 3537 }
702422bd 3538 }
702422bd 3539
7dcef374
TW
3540 peasycap->frame_fill = 0;
3541 peasycap->frame_read = 0;
3542 JOM(4, "allocation of frame buffers done: %i pages\n", k *
3543 m);
3544/*---------------------------------------------------------------------------*/
3545 JOM(4, "allocating %i field buffers of size %li\n",
3546 FIELD_BUFFER_MANY, (long int)FIELD_BUFFER_SIZE);
3547 JOM(4, ".... each scattered over %li pages\n",
3548 FIELD_BUFFER_SIZE/PAGE_SIZE);
3549
3550 for (k = 0; k < FIELD_BUFFER_MANY; k++) {
3551 for (m = 0; m < FIELD_BUFFER_SIZE/PAGE_SIZE; m++) {
6888393c 3552 if (peasycap->field_buffer[k][m].pgo) {
7dcef374
TW
3553 SAM("ERROR: attempting to reallocate "
3554 "field buffers\n");
3555 } else {
3556 pbuf = (void *) __get_free_page(GFP_KERNEL);
6888393c 3557 if (!pbuf) {
7dcef374
TW
3558 SAM("ERROR: Could not allocate field"
3559 " buffer %i page %i\n", k, m);
3560 return -ENOMEM;
3561 }
3562 else
3563 peasycap->allocation_video_page += 1;
3564 peasycap->field_buffer[k][m].pgo = pbuf;
702422bd 3565 }
7dcef374
TW
3566 peasycap->field_buffer[k][m].pto =
3567 peasycap->field_buffer[k][m].pgo;
3568 }
3569 peasycap->field_buffer[k][0].kount = 0x0200;
702422bd 3570 }
7dcef374
TW
3571 peasycap->field_fill = 0;
3572 peasycap->field_page = 0;
3573 peasycap->field_read = 0;
3574 JOM(4, "allocation of field buffers done: %i pages\n", k *
3575 m);
3576/*---------------------------------------------------------------------------*/
3577 JOM(4, "allocating %i isoc video buffers of size %i\n",
3578 VIDEO_ISOC_BUFFER_MANY,
3579 peasycap->video_isoc_buffer_size);
3580 JOM(4, ".... each occupying contiguous memory pages\n");
3581
3582 for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
a90f3620
TW
3583 pbuf = (void *)__get_free_pages(GFP_KERNEL,
3584 VIDEO_ISOC_ORDER);
6888393c 3585 if (!pbuf) {
7dcef374
TW
3586 SAM("ERROR: Could not allocate isoc video buffer "
3587 "%i\n", k);
3588 return -ENOMEM;
3589 } else
3590 peasycap->allocation_video_page +=
a90f3620 3591 BIT(VIDEO_ISOC_ORDER);
702422bd 3592
7dcef374 3593 peasycap->video_isoc_buffer[k].pgo = pbuf;
a90f3620
TW
3594 peasycap->video_isoc_buffer[k].pto =
3595 pbuf + peasycap->video_isoc_buffer_size;
7dcef374
TW
3596 peasycap->video_isoc_buffer[k].kount = k;
3597 }
3598 JOM(4, "allocation of isoc video buffers done: %i pages\n",
3599 k * (0x01 << VIDEO_ISOC_ORDER));
702422bd
T
3600/*---------------------------------------------------------------------------*/
3601/*
3602 * ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
3603 */
3604/*---------------------------------------------------------------------------*/
7dcef374
TW
3605 JOM(4, "allocating %i struct urb.\n", VIDEO_ISOC_BUFFER_MANY);
3606 JOM(4, "using %i=peasycap->video_isoc_framesperdesc\n",
3607 peasycap->video_isoc_framesperdesc);
3608 JOM(4, "using %i=peasycap->video_isoc_maxframesize\n",
3609 peasycap->video_isoc_maxframesize);
3610 JOM(4, "using %i=peasycap->video_isoc_buffer_sizen",
3611 peasycap->video_isoc_buffer_size);
3612
3613 for (k = 0; k < VIDEO_ISOC_BUFFER_MANY; k++) {
3614 purb = usb_alloc_urb(peasycap->video_isoc_framesperdesc,
3615 GFP_KERNEL);
6888393c 3616 if (!purb) {
7dcef374
TW
3617 SAM("ERROR: usb_alloc_urb returned NULL for buffer "
3618 "%i\n", k);
3619 return -ENOMEM;
3620 } else
3621 peasycap->allocation_video_urb += 1;
702422bd 3622/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
7dcef374 3623 pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
6888393c 3624 if (!pdata_urb) {
7dcef374
TW
3625 SAM("ERROR: Could not allocate struct data_urb.\n");
3626 return -ENOMEM;
3627 } else
3628 peasycap->allocation_video_struct +=
3629 sizeof(struct data_urb);
702422bd 3630
7dcef374
TW
3631 pdata_urb->purb = purb;
3632 pdata_urb->isbuf = k;
3633 pdata_urb->length = 0;
3634 list_add_tail(&(pdata_urb->list_head),
3635 peasycap->purb_video_head);
702422bd
T
3636/*---------------------------------------------------------------------------*/
3637/*
3638 * ... AND INITIALIZE THEM
3639 */
3640/*---------------------------------------------------------------------------*/
7dcef374
TW
3641 if (!k) {
3642 JOM(4, "initializing video urbs thus:\n");
3643 JOM(4, " purb->interval = 1;\n");
3644 JOM(4, " purb->dev = peasycap->pusb_device;\n");
3645 JOM(4, " purb->pipe = usb_rcvisocpipe"
3646 "(peasycap->pusb_device,%i);\n",
3647 peasycap->video_endpointnumber);
3648 JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
3649 JOM(4, " purb->transfer_buffer = peasycap->"
3650 "video_isoc_buffer[.].pgo;\n");
3651 JOM(4, " purb->transfer_buffer_length = %i;\n",
3652 peasycap->video_isoc_buffer_size);
3653 JOM(4, " purb->complete = easycap_complete;\n");
3654 JOM(4, " purb->context = peasycap;\n");
3655 JOM(4, " purb->start_frame = 0;\n");
3656 JOM(4, " purb->number_of_packets = %i;\n",
3657 peasycap->video_isoc_framesperdesc);
3658 JOM(4, " for (j = 0; j < %i; j++)\n",
3659 peasycap->video_isoc_framesperdesc);
3660 JOM(4, " {\n");
3661 JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
3662 peasycap->video_isoc_maxframesize);
3663 JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
3664 peasycap->video_isoc_maxframesize);
3665 JOM(4, " }\n");
3666 }
702422bd 3667
7dcef374
TW
3668 purb->interval = 1;
3669 purb->dev = peasycap->pusb_device;
3670 purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
3671 peasycap->video_endpointnumber);
3672 purb->transfer_flags = URB_ISO_ASAP;
3673 purb->transfer_buffer = peasycap->video_isoc_buffer[k].pgo;
3674 purb->transfer_buffer_length =
3675 peasycap->video_isoc_buffer_size;
3676 purb->complete = easycap_complete;
3677 purb->context = peasycap;
3678 purb->start_frame = 0;
3679 purb->number_of_packets = peasycap->video_isoc_framesperdesc;
3680 for (j = 0; j < peasycap->video_isoc_framesperdesc; j++) {
3681 purb->iso_frame_desc[j].offset = j *
3682 peasycap->video_isoc_maxframesize;
3683 purb->iso_frame_desc[j].length =
3684 peasycap->video_isoc_maxframesize;
3685 }
702422bd 3686 }
7dcef374 3687 JOM(4, "allocation of %i struct urb done.\n", k);
702422bd
T
3688/*--------------------------------------------------------------------------*/
3689/*
3690 * SAVE POINTER peasycap IN THIS INTERFACE.
3691 */
3692/*--------------------------------------------------------------------------*/
11ff12fe 3693 usb_set_intfdata(intf, peasycap);
268dfede
MT
3694/*---------------------------------------------------------------------------*/
3695/*
3696 * IT IS ESSENTIAL TO INITIALIZE THE HARDWARE BEFORE, RATHER THAN AFTER,
3697 * THE DEVICE IS REGISTERED, BECAUSE SOME VERSIONS OF THE videodev MODULE
3698 * CALL easycap_open() IMMEDIATELY AFTER REGISTRATION, CAUSING A CLASH.
3699 * BEWARE.
3700*/
3701/*---------------------------------------------------------------------------*/
8d613954
TW
3702 peasycap->ntsc = easycap_ntsc;
3703 JOM(8, "defaulting initially to %s\n",
3704 easycap_ntsc ? "NTSC" : "PAL");
7dcef374
TW
3705 rc = reset(peasycap);
3706 if (rc) {
c7506658 3707 SAM("ERROR: reset() rc = %i\n", rc);
7dcef374
TW
3708 return -EFAULT;
3709 }
702422bd
T
3710/*--------------------------------------------------------------------------*/
3711/*
3712 * THE VIDEO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
3713 */
3714/*--------------------------------------------------------------------------*/
cdaa898b 3715 if (v4l2_device_register(&intf->dev, &peasycap->v4l2_device)) {
7dcef374
TW
3716 SAM("v4l2_device_register() failed\n");
3717 return -ENODEV;
7dcef374 3718 }
cdaa898b
TW
3719 JOM(4, "registered device instance: %s\n",
3720 peasycap->v4l2_device.name);
e68703cf
MT
3721/*---------------------------------------------------------------------------*/
3722/*
a9855917 3723 * FIXME
ae59dad4
MT
3724 *
3725 *
e68703cf
MT
3726 * THIS IS BELIEVED TO BE HARMLESS, BUT MAY WELL BE UNNECESSARY OR WRONG:
3727*/
3728/*---------------------------------------------------------------------------*/
7dcef374 3729 peasycap->video_device.v4l2_dev = NULL;
e68703cf 3730/*---------------------------------------------------------------------------*/
702422bd 3731
e68703cf 3732
7dcef374 3733 strcpy(&peasycap->video_device.name[0], "easycapdc60");
7dcef374 3734 peasycap->video_device.fops = &v4l2_fops;
7dcef374
TW
3735 peasycap->video_device.minor = -1;
3736 peasycap->video_device.release = (void *)(&videodev_release);
702422bd 3737
7dcef374 3738 video_set_drvdata(&(peasycap->video_device), (void *)peasycap);
702422bd 3739
7dcef374
TW
3740 if (0 != (video_register_device(&(peasycap->video_device),
3741 VFL_TYPE_GRABBER, -1))) {
3742 err("Not able to register with videodev");
3743 videodev_release(&(peasycap->video_device));
3744 return -ENODEV;
3745 } else {
3746 (peasycap->registered_video)++;
3747 SAM("registered with videodev: %i=minor\n",
3748 peasycap->video_device.minor);
3749 peasycap->minor = peasycap->video_device.minor;
3750 }
e68703cf 3751/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
a9855917 3752
7dcef374 3753 break;
dfcce7bf 3754 }
702422bd
T
3755/*--------------------------------------------------------------------------*/
3756/*
3757 * INTERFACE 1 IS THE AUDIO CONTROL INTERFACE
3758 * INTERFACE 2 IS THE AUDIO STREAMING INTERFACE
3759 */
3760/*--------------------------------------------------------------------------*/
7dcef374 3761 case 1: {
7dcef374
TW
3762 if (!peasycap) {
3763 SAM("MISTAKE: peasycap is NULL\n");
3764 return -EFAULT;
3765 }
702422bd
T
3766/*--------------------------------------------------------------------------*/
3767/*
3768 * SAVE POINTER peasycap IN INTERFACE 1
3769 */
3770/*--------------------------------------------------------------------------*/
11ff12fe 3771 usb_set_intfdata(intf, peasycap);
7dcef374 3772 JOM(4, "no initialization required for interface %i\n",
11ff12fe 3773 interface->bInterfaceNumber);
7dcef374 3774 break;
702422bd 3775 }
c7506658 3776/*--------------------------------------------------------------------------*/
7dcef374 3777 case 2: {
7dcef374
TW
3778 if (!peasycap) {
3779 SAM("MISTAKE: peasycap is NULL\n");
3780 return -EFAULT;
3781 }
3782 if (!isokalt) {
3783 SAM("ERROR: no viable audio_altsetting_on\n");
3784 return -ENOENT;
3785 } else {
3786 peasycap->audio_altsetting_on = okalt[isokalt - 1];
3787 JOM(4, "%i=audio_altsetting_on <====\n",
3788 peasycap->audio_altsetting_on);
3789 }
e68703cf 3790
7dcef374
TW
3791 peasycap->audio_endpointnumber = okepn[isokalt - 1];
3792 JOM(4, "%i=audio_endpointnumber\n", peasycap->audio_endpointnumber);
e68703cf 3793
7dcef374
TW
3794 peasycap->audio_isoc_maxframesize = okmps[isokalt - 1];
3795 JOM(4, "%i=audio_isoc_maxframesize\n",
3796 peasycap->audio_isoc_maxframesize);
3797 if (0 >= peasycap->audio_isoc_maxframesize) {
3798 SAM("ERROR: bad audio_isoc_maxframesize\n");
3799 return -ENOENT;
3800 }
3801 if (9 == peasycap->audio_isoc_maxframesize) {
3802 peasycap->ilk |= 0x02;
3803 SAM("audio hardware is microphone\n");
3804 peasycap->microphone = true;
a90f3620
TW
3805 peasycap->audio_pages_per_fragment =
3806 PAGES_PER_AUDIO_FRAGMENT;
7dcef374
TW
3807 } else if (256 == peasycap->audio_isoc_maxframesize) {
3808 peasycap->ilk &= ~0x02;
3809 SAM("audio hardware is AC'97\n");
3810 peasycap->microphone = false;
a90f3620
TW
3811 peasycap->audio_pages_per_fragment =
3812 PAGES_PER_AUDIO_FRAGMENT;
7dcef374
TW
3813 } else {
3814 SAM("hardware is unidentified:\n");
3815 SAM("%i=audio_isoc_maxframesize\n",
a90f3620 3816 peasycap->audio_isoc_maxframesize);
7dcef374
TW
3817 return -ENOENT;
3818 }
702422bd 3819
7dcef374 3820 peasycap->audio_bytes_per_fragment =
a90f3620 3821 peasycap->audio_pages_per_fragment * PAGE_SIZE;
7dcef374 3822 peasycap->audio_buffer_page_many = (AUDIO_FRAGMENT_MANY *
a90f3620 3823 peasycap->audio_pages_per_fragment);
7dcef374
TW
3824
3825 JOM(4, "%6i=AUDIO_FRAGMENT_MANY\n", AUDIO_FRAGMENT_MANY);
3826 JOM(4, "%6i=audio_pages_per_fragment\n",
3827 peasycap->audio_pages_per_fragment);
3828 JOM(4, "%6i=audio_bytes_per_fragment\n",
3829 peasycap->audio_bytes_per_fragment);
3830 JOM(4, "%6i=audio_buffer_page_many\n",
3831 peasycap->audio_buffer_page_many);
3832
3833 peasycap->audio_isoc_framesperdesc = AUDIO_ISOC_FRAMESPERDESC;
3834
3835 JOM(4, "%i=audio_isoc_framesperdesc\n",
3836 peasycap->audio_isoc_framesperdesc);
3837 if (0 >= peasycap->audio_isoc_framesperdesc) {
3838 SAM("ERROR: bad audio_isoc_framesperdesc\n");
3839 return -ENOENT;
3840 }
702422bd 3841
7dcef374
TW
3842 peasycap->audio_isoc_buffer_size =
3843 peasycap->audio_isoc_maxframesize *
3844 peasycap->audio_isoc_framesperdesc;
3845 JOM(4, "%i=audio_isoc_buffer_size\n",
3846 peasycap->audio_isoc_buffer_size);
3847 if (AUDIO_ISOC_BUFFER_SIZE < peasycap->audio_isoc_buffer_size) {
3848 SAM("MISTAKE: audio_isoc_buffer_size bigger "
3849 "than %li=AUDIO_ISOC_BUFFER_SIZE\n",
3850 AUDIO_ISOC_BUFFER_SIZE);
3851 return -EFAULT;
3852 }
3853 if (-1 == peasycap->audio_interface) {
3854 SAM("MISTAKE: audio_interface is unset\n");
3855 return -EFAULT;
3856 }
3857 if (-1 == peasycap->audio_altsetting_on) {
3858 SAM("MISTAKE: audio_altsetting_on is unset\n");
3859 return -EFAULT;
3860 }
3861 if (-1 == peasycap->audio_altsetting_off) {
3862 SAM("MISTAKE: audio_interface_off is unset\n");
3863 return -EFAULT;
3864 }
3865 if (-1 == peasycap->audio_endpointnumber) {
3866 SAM("MISTAKE: audio_endpointnumber is unset\n");
3867 return -EFAULT;
3868 }
3869 if (-1 == peasycap->audio_isoc_maxframesize) {
3870 SAM("MISTAKE: audio_isoc_maxframesize is unset\n");
3871 return -EFAULT;
3872 }
3873 if (-1 == peasycap->audio_isoc_buffer_size) {
3874 SAM("MISTAKE: audio_isoc_buffer_size is unset\n");
3875 return -EFAULT;
3876 }
702422bd
T
3877/*---------------------------------------------------------------------------*/
3878/*
3879 * ALLOCATE MEMORY FOR AUDIO BUFFERS. LISTS MUST BE INITIALIZED FIRST.
3880 */
3881/*---------------------------------------------------------------------------*/
7dcef374
TW
3882 INIT_LIST_HEAD(&(peasycap->urb_audio_head));
3883 peasycap->purb_audio_head = &(peasycap->urb_audio_head);
702422bd 3884
702422bd 3885/*---------------------------------------------------------------------------*/
7dcef374 3886 JOM(4, "allocating %i isoc audio buffers of size %i\n",
a90f3620
TW
3887 AUDIO_ISOC_BUFFER_MANY,
3888 peasycap->audio_isoc_buffer_size);
7dcef374 3889 JOM(4, ".... each occupying contiguous memory pages\n");
702422bd 3890
7dcef374 3891 for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
a90f3620
TW
3892 pbuf = (void *)__get_free_pages(GFP_KERNEL,
3893 AUDIO_ISOC_ORDER);
6888393c 3894 if (!pbuf) {
7dcef374
TW
3895 SAM("ERROR: Could not allocate isoc audio buffer "
3896 "%i\n", k);
3897 return -ENOMEM;
3898 } else
3899 peasycap->allocation_audio_page +=
a90f3620 3900 BIT(AUDIO_ISOC_ORDER);
702422bd 3901
7dcef374
TW
3902 peasycap->audio_isoc_buffer[k].pgo = pbuf;
3903 peasycap->audio_isoc_buffer[k].pto = pbuf +
3904 peasycap->audio_isoc_buffer_size;
3905 peasycap->audio_isoc_buffer[k].kount = k;
3906 }
3907 JOM(4, "allocation of isoc audio buffers done.\n");
702422bd
T
3908/*---------------------------------------------------------------------------*/
3909/*
3910 * ALLOCATE AND INITIALIZE MULTIPLE struct urb ...
3911 */
3912/*---------------------------------------------------------------------------*/
7dcef374
TW
3913 JOM(4, "allocating %i struct urb.\n", AUDIO_ISOC_BUFFER_MANY);
3914 JOM(4, "using %i=peasycap->audio_isoc_framesperdesc\n",
a90f3620 3915 peasycap->audio_isoc_framesperdesc);
7dcef374 3916 JOM(4, "using %i=peasycap->audio_isoc_maxframesize\n",
a90f3620 3917 peasycap->audio_isoc_maxframesize);
7dcef374 3918 JOM(4, "using %i=peasycap->audio_isoc_buffer_size\n",
a90f3620 3919 peasycap->audio_isoc_buffer_size);
7dcef374
TW
3920
3921 for (k = 0; k < AUDIO_ISOC_BUFFER_MANY; k++) {
3922 purb = usb_alloc_urb(peasycap->audio_isoc_framesperdesc,
a90f3620 3923 GFP_KERNEL);
6888393c 3924 if (!purb) {
7dcef374
TW
3925 SAM("ERROR: usb_alloc_urb returned NULL for buffer "
3926 "%i\n", k);
3927 return -ENOMEM;
e03da5e2
TW
3928 }
3929 peasycap->allocation_audio_urb += 1 ;
702422bd 3930/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
7dcef374 3931 pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
6888393c 3932 if (!pdata_urb) {
7dcef374
TW
3933 SAM("ERROR: Could not allocate struct data_urb.\n");
3934 return -ENOMEM;
e03da5e2
TW
3935 }
3936 peasycap->allocation_audio_struct +=
3937 sizeof(struct data_urb);
702422bd 3938
7dcef374
TW
3939 pdata_urb->purb = purb;
3940 pdata_urb->isbuf = k;
3941 pdata_urb->length = 0;
3942 list_add_tail(&(pdata_urb->list_head),
3943 peasycap->purb_audio_head);
702422bd
T
3944/*---------------------------------------------------------------------------*/
3945/*
3946 * ... AND INITIALIZE THEM
3947 */
3948/*---------------------------------------------------------------------------*/
7dcef374
TW
3949 if (!k) {
3950 JOM(4, "initializing audio urbs thus:\n");
3951 JOM(4, " purb->interval = 1;\n");
3952 JOM(4, " purb->dev = peasycap->pusb_device;\n");
3953 JOM(4, " purb->pipe = usb_rcvisocpipe(peasycap->"
3954 "pusb_device,%i);\n",
3955 peasycap->audio_endpointnumber);
3956 JOM(4, " purb->transfer_flags = URB_ISO_ASAP;\n");
3957 JOM(4, " purb->transfer_buffer = "
3958 "peasycap->audio_isoc_buffer[.].pgo;\n");
3959 JOM(4, " purb->transfer_buffer_length = %i;\n",
a90f3620 3960 peasycap->audio_isoc_buffer_size);
7dcef374 3961 JOM(4, " purb->complete = easycap_alsa_complete;\n");
7dcef374
TW
3962 JOM(4, " purb->context = peasycap;\n");
3963 JOM(4, " purb->start_frame = 0;\n");
3964 JOM(4, " purb->number_of_packets = %i;\n",
3965 peasycap->audio_isoc_framesperdesc);
3966 JOM(4, " for (j = 0; j < %i; j++)\n",
3967 peasycap->audio_isoc_framesperdesc);
3968 JOM(4, " {\n");
3969 JOM(4, " purb->iso_frame_desc[j].offset = j*%i;\n",
a90f3620 3970 peasycap->audio_isoc_maxframesize);
7dcef374 3971 JOM(4, " purb->iso_frame_desc[j].length = %i;\n",
a90f3620 3972 peasycap->audio_isoc_maxframesize);
7dcef374 3973 JOM(4, " }\n");
dfcce7bf 3974 }
702422bd 3975
7dcef374
TW
3976 purb->interval = 1;
3977 purb->dev = peasycap->pusb_device;
3978 purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
3979 peasycap->audio_endpointnumber);
3980 purb->transfer_flags = URB_ISO_ASAP;
3981 purb->transfer_buffer = peasycap->audio_isoc_buffer[k].pgo;
3982 purb->transfer_buffer_length =
3983 peasycap->audio_isoc_buffer_size;
7dcef374 3984 purb->complete = easycap_alsa_complete;
7dcef374
TW
3985 purb->context = peasycap;
3986 purb->start_frame = 0;
3987 purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
3988 for (j = 0; j < peasycap->audio_isoc_framesperdesc; j++) {
3989 purb->iso_frame_desc[j].offset = j *
3990 peasycap->audio_isoc_maxframesize;
3991 purb->iso_frame_desc[j].length =
3992 peasycap->audio_isoc_maxframesize;
3993 }
702422bd 3994 }
7dcef374 3995 JOM(4, "allocation of %i struct urb done.\n", k);
702422bd
T
3996/*---------------------------------------------------------------------------*/
3997/*
3998 * SAVE POINTER peasycap IN THIS INTERFACE.
3999 */
4000/*---------------------------------------------------------------------------*/
11ff12fe 4001 usb_set_intfdata(intf, peasycap);
702422bd
T
4002/*---------------------------------------------------------------------------*/
4003/*
4004 * THE AUDIO DEVICE CAN BE REGISTERED NOW, AS IT IS READY.
4005 */
4006/*---------------------------------------------------------------------------*/
7dcef374 4007 JOM(4, "initializing ALSA card\n");
a9855917 4008
7dcef374
TW
4009 rc = easycap_alsa_probe(peasycap);
4010 if (rc) {
c7506658 4011 err("easycap_alsa_probe() rc = %i\n", rc);
7dcef374 4012 return -ENODEV;
7dcef374 4013 }
a9855917 4014
a9855917 4015
ad30d7af
TW
4016 JOM(8, "kref_get() with %i=kref.refcount.counter\n",
4017 peasycap->kref.refcount.counter);
4018 kref_get(&peasycap->kref);
4019 peasycap->registered_audio++;
7dcef374 4020 break;
dfcce7bf 4021 }
702422bd
T
4022/*---------------------------------------------------------------------------*/
4023/*
4024 * INTERFACES OTHER THAN 0, 1 AND 2 ARE UNEXPECTED
4025 */
4026/*---------------------------------------------------------------------------*/
dfcce7bf
TW
4027 default:
4028 JOM(4, "ERROR: unexpected interface %i\n", bInterfaceNumber);
4029 return -EINVAL;
7dcef374 4030 }
e03da5e2 4031 SAM("ends successfully for interface %i\n", bInterfaceNumber);
7dcef374 4032 return 0;
702422bd
T
4033}
4034/*****************************************************************************/
4035/*---------------------------------------------------------------------------*/
4036/*
ae59dad4
MT
4037 * WHEN THIS FUNCTION IS CALLED THE EasyCAP HAS ALREADY BEEN PHYSICALLY
4038 * UNPLUGGED. HENCE peasycap->pusb_device IS NO LONGER VALID.
a9855917 4039 *
73019286 4040 * THIS FUNCTION AFFECTS ALSA. BEWARE.
702422bd
T
4041 */
4042/*---------------------------------------------------------------------------*/
d090bf57 4043static void easycap_usb_disconnect(struct usb_interface *pusb_interface)
702422bd 4044{
7dcef374
TW
4045 struct usb_host_interface *pusb_host_interface;
4046 struct usb_interface_descriptor *pusb_interface_descriptor;
4047 u8 bInterfaceNumber;
4048 struct easycap *peasycap;
4049
4050 struct list_head *plist_head;
4051 struct data_urb *pdata_urb;
4052 int minor, m, kd;
702422bd 4053
7dcef374 4054 JOT(4, "\n");
702422bd 4055
7dcef374 4056 pusb_host_interface = pusb_interface->cur_altsetting;
6888393c 4057 if (!pusb_host_interface) {
7dcef374
TW
4058 JOT(4, "ERROR: pusb_host_interface is NULL\n");
4059 return;
4060 }
4061 pusb_interface_descriptor = &(pusb_host_interface->desc);
6888393c 4062 if (!pusb_interface_descriptor) {
7dcef374
TW
4063 JOT(4, "ERROR: pusb_interface_descriptor is NULL\n");
4064 return;
4065 }
4066 bInterfaceNumber = pusb_interface_descriptor->bInterfaceNumber;
4067 minor = pusb_interface->minor;
4068 JOT(4, "intf[%i]: minor=%i\n", bInterfaceNumber, minor);
702422bd 4069
7dcef374
TW
4070 if (1 == bInterfaceNumber)
4071 return;
e68703cf 4072
7dcef374 4073 peasycap = usb_get_intfdata(pusb_interface);
6888393c 4074 if (!peasycap) {
7dcef374
TW
4075 SAY("ERROR: peasycap is NULL\n");
4076 return;
4077 }
e68703cf
MT
4078/*---------------------------------------------------------------------------*/
4079/*
4080 * IF THE WAIT QUEUES ARE NOT CLEARED A DEADLOCK IS POSSIBLE. BEWARE.
4081*/
4082/*---------------------------------------------------------------------------*/
7dcef374
TW
4083 peasycap->video_eof = 1;
4084 peasycap->audio_eof = 1;
4085 wake_up_interruptible(&(peasycap->wq_video));
4086 wake_up_interruptible(&(peasycap->wq_audio));
4087/*---------------------------------------------------------------------------*/
4088 switch (bInterfaceNumber) {
4089 case 0: {
6888393c 4090 if (peasycap->purb_video_head) {
7dcef374
TW
4091 JOM(4, "killing video urbs\n");
4092 m = 0;
a90f3620 4093 list_for_each(plist_head, peasycap->purb_video_head) {
7dcef374
TW
4094 pdata_urb = list_entry(plist_head,
4095 struct data_urb, list_head);
6888393c
TW
4096 if (pdata_urb) {
4097 if (pdata_urb->purb) {
7dcef374
TW
4098 usb_kill_urb(pdata_urb->purb);
4099 m++;
4100 }
702422bd
T
4101 }
4102 }
7dcef374 4103 JOM(4, "%i video urbs killed\n", m);
e68703cf 4104 }
7dcef374 4105 break;
702422bd
T
4106 }
4107/*---------------------------------------------------------------------------*/
7dcef374 4108 case 2: {
6888393c 4109 if (peasycap->purb_audio_head) {
7dcef374
TW
4110 JOM(4, "killing audio urbs\n");
4111 m = 0;
a90f3620 4112 list_for_each(plist_head, peasycap->purb_audio_head) {
7dcef374
TW
4113 pdata_urb = list_entry(plist_head,
4114 struct data_urb, list_head);
6888393c
TW
4115 if (pdata_urb) {
4116 if (pdata_urb->purb) {
7dcef374
TW
4117 usb_kill_urb(pdata_urb->purb);
4118 m++;
4119 }
702422bd
T
4120 }
4121 }
7dcef374 4122 JOM(4, "%i audio urbs killed\n", m);
e68703cf 4123 }
7dcef374 4124 break;
702422bd 4125 }
7dcef374
TW
4126 default:
4127 break;
c7506658 4128 }
702422bd
T
4129/*--------------------------------------------------------------------------*/
4130/*
4131 * DEREGISTER
ae59dad4
MT
4132 *
4133 * THIS PROCEDURE WILL BLOCK UNTIL easycap_poll(), VIDEO IOCTL AND AUDIO
4134 * IOCTL ARE ALL UNLOCKED. IF THIS IS NOT DONE AN Oops CAN OCCUR WHEN
4135 * AN EasyCAP IS UNPLUGGED WHILE THE URBS ARE RUNNING. BEWARE.
702422bd
T
4136 */
4137/*--------------------------------------------------------------------------*/
c7506658
TW
4138 kd = isdongle(peasycap);
4139 switch (bInterfaceNumber) {
4140 case 0: {
4141 if (0 <= kd && DONGLE_MANY > kd) {
4142 wake_up_interruptible(&peasycap->wq_video);
4143 JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
4144 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
ae59dad4 4145 mutex_video)) {
c7506658
TW
4146 SAY("ERROR: "
4147 "cannot lock dongle[%i].mutex_video\n", kd);
4148 return;
4149 }
4150 JOM(4, "locked dongle[%i].mutex_video\n", kd);
4151 } else {
4152 SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
ae59dad4 4153 }
ae59dad4 4154/*---------------------------------------------------------------------------*/
c7506658
TW
4155 if (!peasycap->v4l2_device.name[0]) {
4156 SAM("ERROR: peasycap->v4l2_device.name is empty\n");
4157 if (0 <= kd && DONGLE_MANY > kd)
4158 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
4159 return;
4160 }
4161 v4l2_device_disconnect(&peasycap->v4l2_device);
4162 JOM(4, "v4l2_device_disconnect() OK\n");
4163 v4l2_device_unregister(&peasycap->v4l2_device);
4164 JOM(4, "v4l2_device_unregister() OK\n");
4165
4166 video_unregister_device(&peasycap->video_device);
4167 JOM(4, "intf[%i]: video_unregister_device() minor=%i\n",
4168 bInterfaceNumber, minor);
4169 peasycap->registered_video--;
268dfede
MT
4170/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
4171
c7506658
TW
4172 if (0 <= kd && DONGLE_MANY > kd) {
4173 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
4174 JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
4175 }
4176 break;
ae59dad4 4177 }
c7506658
TW
4178 case 2: {
4179 if (0 <= kd && DONGLE_MANY > kd) {
4180 wake_up_interruptible(&peasycap->wq_audio);
4181 JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
4182 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].
ae59dad4 4183 mutex_audio)) {
c7506658
TW
4184 SAY("ERROR: "
4185 "cannot lock dongle[%i].mutex_audio\n", kd);
4186 return;
4187 }
4188 JOM(4, "locked dongle[%i].mutex_audio\n", kd);
4189 } else
4190 SAY("ERROR: %i=kd is bad: cannot lock dongle\n", kd);
c7506658
TW
4191 if (0 != snd_card_free(peasycap->psnd_card)) {
4192 SAY("ERROR: snd_card_free() failed\n");
4193 } else {
4194 peasycap->psnd_card = NULL;
4195 (peasycap->registered_audio)--;
4196 }
c7506658
TW
4197 if (0 <= kd && DONGLE_MANY > kd) {
4198 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
4199 JOM(4, "unlocked dongle[%i].mutex_audio\n", kd);
4200 }
4201 break;
4202 }
4203 default:
4204 break;
ae59dad4 4205 }
702422bd
T
4206/*---------------------------------------------------------------------------*/
4207/*
4208 * CALL easycap_delete() IF NO REMAINING REFERENCES TO peasycap
a9855917 4209 * (ALSO WHEN ALSA HAS BEEN IN USE)
702422bd
T
4210 */
4211/*---------------------------------------------------------------------------*/
c7506658
TW
4212 if (!peasycap->kref.refcount.counter) {
4213 SAM("ERROR: peasycap->kref.refcount.counter is zero "
4214 "so cannot call kref_put()\n");
ae59dad4
MT
4215 SAM("ending unsuccessfully: may cause memory leak\n");
4216 return;
4217 }
c7506658
TW
4218 if (0 <= kd && DONGLE_MANY > kd) {
4219 JOM(4, "about to lock dongle[%i].mutex_video\n", kd);
4220 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_video)) {
4221 SAY("ERROR: cannot lock dongle[%i].mutex_video\n", kd);
4222 SAM("ending unsuccessfully: may cause memory leak\n");
4223 return;
4224 }
4225 JOM(4, "locked dongle[%i].mutex_video\n", kd);
4226 JOM(4, "about to lock dongle[%i].mutex_audio\n", kd);
4227 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
4228 SAY("ERROR: cannot lock dongle[%i].mutex_audio\n", kd);
4229 mutex_unlock(&(easycapdc60_dongle[kd].mutex_video));
4230 JOM(4, "unlocked dongle[%i].mutex_video\n", kd);
4231 SAM("ending unsuccessfully: may cause memory leak\n");
4232 return;
4233 }
4234 JOM(4, "locked dongle[%i].mutex_audio\n", kd);
4235 }
4236 JOM(4, "intf[%i]: %i=peasycap->kref.refcount.counter\n",
4237 bInterfaceNumber, (int)peasycap->kref.refcount.counter);
4238 kref_put(&peasycap->kref, easycap_delete);
4239 JOT(4, "intf[%i]: kref_put() done.\n", bInterfaceNumber);
4240 if (0 <= kd && DONGLE_MANY > kd) {
4241 mutex_unlock(&(easycapdc60_dongle[kd].mutex_audio));
4242 JOT(4, "unlocked dongle[%i].mutex_audio\n", kd);
4243 mutex_unlock(&easycapdc60_dongle[kd].mutex_video);
4244 JOT(4, "unlocked dongle[%i].mutex_video\n", kd);
4245 }
702422bd 4246/*---------------------------------------------------------------------------*/
c7506658
TW
4247 JOM(4, "ends\n");
4248 return;
702422bd
T
4249}
4250/*****************************************************************************/
a9855917 4251
702422bd
T
4252/*---------------------------------------------------------------------------*/
4253/*
d090bf57 4254 * PARAMETERS APPLICABLE TO ENTIRE DRIVER, I.E. BOTH VIDEO AND AUDIO
702422bd
T
4255 */
4256/*---------------------------------------------------------------------------*/
d090bf57
TW
4257static struct usb_device_id easycap_usb_device_id_table[] = {
4258 {USB_DEVICE(USB_EASYCAP_VENDOR_ID, USB_EASYCAP_PRODUCT_ID)},
4259 { }
4260};
4261
4262MODULE_DEVICE_TABLE(usb, easycap_usb_device_id_table);
4263struct usb_driver easycap_usb_driver = {
4264 .name = "easycap",
4265 .id_table = easycap_usb_device_id_table,
4266 .probe = easycap_usb_probe,
4267 .disconnect = easycap_usb_disconnect,
4268};
702422bd 4269
d090bf57
TW
4270static int __init easycap_module_init(void)
4271{
4272 int k, rc;
4273
aff512c8
TW
4274 printk(KERN_INFO "Easycap version: "EASYCAP_DRIVER_VERSION "\n");
4275
d090bf57
TW
4276 JOT(4, "begins. %i=debug %i=bars %i=gain\n",
4277 easycap_debug, easycap_bars, easycap_gain);
d090bf57
TW
4278
4279 mutex_init(&mutex_dongle);
4280 for (k = 0; k < DONGLE_MANY; k++) {
3c1fb66e 4281 easycapdc60_dongle[k].peasycap = NULL;
d090bf57
TW
4282 mutex_init(&easycapdc60_dongle[k].mutex_video);
4283 mutex_init(&easycapdc60_dongle[k].mutex_audio);
4284 }
d090bf57 4285 rc = usb_register(&easycap_usb_driver);
6911e7e4 4286 if (rc)
aff512c8 4287 printk(KERN_ERR "Easycap: usb_register failed rc=%d\n", rc);
d090bf57 4288
d090bf57 4289 return rc;
702422bd
T
4290}
4291/*****************************************************************************/
dbf4805e 4292static void __exit easycap_module_exit(void)
702422bd 4293{
d090bf57 4294 usb_deregister(&easycap_usb_driver);
702422bd
T
4295}
4296/*****************************************************************************/
4297
4298module_init(easycap_module_init);
4299module_exit(easycap_module_exit);
4300
702422bd 4301/*****************************************************************************/
This page took 0.378943 seconds and 5 git commands to generate.