]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/easycap/easycap_sound.c
Merge branch 'for-2638/i2c/iop' into for-linus/i2c-2638
[karo-tx-linux.git] / drivers / staging / easycap / easycap_sound.c
1 /******************************************************************************
2 *                                                                             *
3 *  easycap_sound.c                                                            *
4 *                                                                             *
5 *  Audio 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"
32 #include "easycap_debug.h"
33 #include "easycap_sound.h"
34
35 /*****************************************************************************/
36 /*---------------------------------------------------------------------------*/
37 /*
38  *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
39  *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
40  *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
41  */
42 /*---------------------------------------------------------------------------*/
43 void
44 easysnd_complete(struct urb *purb)
45 {
46 struct easycap *peasycap;
47 struct data_buffer *paudio_buffer;
48 __u8 *p1, *p2;
49 __s16 s16;
50 int i, j, more, much, leap, rc;
51 #if defined(UPSAMPLE)
52 int k;
53 __s16 oldaudio, newaudio, delta;
54 #endif /*UPSAMPLE*/
55
56 JOT(16, "\n");
57
58 if (NULL == purb) {
59         SAY("ERROR: purb is NULL\n");
60         return;
61 }
62 peasycap = purb->context;
63 if (NULL == peasycap) {
64         SAY("ERROR: peasycap is NULL\n");
65         return;
66 }
67 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
68         SAY("ERROR: bad peasycap\n");
69         return;
70 }
71
72 much = 0;
73
74 if (peasycap->audio_idle) {
75         JOM(16, "%i=audio_idle  %i=audio_isoc_streaming\n", \
76                         peasycap->audio_idle, peasycap->audio_isoc_streaming);
77         if (peasycap->audio_isoc_streaming) {
78                 rc = usb_submit_urb(purb, GFP_ATOMIC);
79                 if (0 != rc) {
80                         if (-ENODEV != rc)
81                                 SAM("ERROR: while %i=audio_idle, " \
82                                         "usb_submit_urb() failed with rc:\n", \
83                                                         peasycap->audio_idle);
84                         switch (rc) {
85                         case -ENOMEM: {
86                                 SAM("-ENOMEM\n");
87                                 break;
88                         }
89                         case -ENODEV: {
90                                 break;
91                         }
92                         case -ENXIO: {
93                                 SAM("-ENXIO\n");
94                                 break;
95                         }
96                         case -EINVAL: {
97                                 SAM("-EINVAL\n");
98                                 break;
99                         }
100                         case -EAGAIN: {
101                                 SAM("-EAGAIN\n");
102                                 break;
103                         }
104                         case -EFBIG: {
105                                 SAM("-EFBIG\n");
106                                 break;
107                         }
108                         case -EPIPE: {
109                                 SAM("-EPIPE\n");
110                                 break;
111                         }
112                         case -EMSGSIZE: {
113                                 SAM("-EMSGSIZE\n");
114                                 break;
115                         }
116                         case -ENOSPC: {
117                                 SAM("-ENOSPC\n");
118                                 break;
119                         }
120                         default: {
121                                 SAM("unknown error: 0x%08X\n", rc);
122                                 break;
123                         }
124                         }
125                 }
126         }
127 return;
128 }
129 /*---------------------------------------------------------------------------*/
130 if (purb->status) {
131         if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
132                 JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
133                 return;
134         }
135         SAM("ERROR: non-zero urb status:\n");
136         switch (purb->status) {
137         case -EINPROGRESS: {
138                 SAM("-EINPROGRESS\n");
139                 break;
140         }
141         case -ENOSR: {
142                 SAM("-ENOSR\n");
143                 break;
144         }
145         case -EPIPE: {
146                 SAM("-EPIPE\n");
147                 break;
148         }
149         case -EOVERFLOW: {
150                 SAM("-EOVERFLOW\n");
151                 break;
152         }
153         case -EPROTO: {
154                 SAM("-EPROTO\n");
155                 break;
156         }
157         case -EILSEQ: {
158                 SAM("-EILSEQ\n");
159                 break;
160         }
161         case -ETIMEDOUT: {
162                 SAM("-ETIMEDOUT\n");
163                 break;
164         }
165         case -EMSGSIZE: {
166                 SAM("-EMSGSIZE\n");
167                 break;
168         }
169         case -EOPNOTSUPP: {
170                 SAM("-EOPNOTSUPP\n");
171                 break;
172         }
173         case -EPFNOSUPPORT: {
174                 SAM("-EPFNOSUPPORT\n");
175                 break;
176         }
177         case -EAFNOSUPPORT: {
178                 SAM("-EAFNOSUPPORT\n");
179                 break;
180         }
181         case -EADDRINUSE: {
182                 SAM("-EADDRINUSE\n");
183                 break;
184         }
185         case -EADDRNOTAVAIL: {
186                 SAM("-EADDRNOTAVAIL\n");
187                 break;
188         }
189         case -ENOBUFS: {
190                 SAM("-ENOBUFS\n");
191                 break;
192         }
193         case -EISCONN: {
194                 SAM("-EISCONN\n");
195                 break;
196         }
197         case -ENOTCONN: {
198                 SAM("-ENOTCONN\n");
199                 break;
200         }
201         case -ESHUTDOWN: {
202                 SAM("-ESHUTDOWN\n");
203                 break;
204         }
205         case -ENOENT: {
206                 SAM("-ENOENT\n");
207                 break;
208         }
209         case -ECONNRESET: {
210                 SAM("-ECONNRESET\n");
211                 break;
212         }
213         case -ENOSPC: {
214                 SAM("ENOSPC\n");
215                 break;
216         }
217         default: {
218                 SAM("unknown error code 0x%08X\n", purb->status);
219                 break;
220         }
221         }
222 /*---------------------------------------------------------------------------*/
223 /*
224  *  RESUBMIT THIS URB AFTER AN ERROR
225  *
226  *  (THIS IS DUPLICATE CODE TO REDUCE INDENTATION OF THE NO-ERROR PATH)
227  */
228 /*---------------------------------------------------------------------------*/
229         if (peasycap->audio_isoc_streaming) {
230                 rc = usb_submit_urb(purb, GFP_ATOMIC);
231                 if (0 != rc) {
232                         SAM("ERROR: while %i=audio_idle, usb_submit_urb() "
233                                 "failed with rc:\n", peasycap->audio_idle);
234                         switch (rc) {
235                         case -ENOMEM: {
236                                 SAM("-ENOMEM\n");
237                                 break;
238                         }
239                         case -ENODEV: {
240                                 SAM("-ENODEV\n");
241                                 break;
242                         }
243                         case -ENXIO: {
244                                 SAM("-ENXIO\n");
245                                 break;
246                         }
247                         case -EINVAL: {
248                                 SAM("-EINVAL\n");
249                                 break;
250                         }
251                         case -EAGAIN: {
252                                 SAM("-EAGAIN\n");
253                                 break;
254                         }
255                         case -EFBIG: {
256                                 SAM("-EFBIG\n");
257                                 break;
258                         }
259                         case -EPIPE: {
260                                 SAM("-EPIPE\n");
261                                 break;
262                         }
263                         case -EMSGSIZE: {
264                                 SAM("-EMSGSIZE\n");
265                                 break;
266                         }
267                         default: {
268                                 SAM("0x%08X\n", rc); break;
269                         }
270                         }
271                 }
272         }
273         return;
274 }
275 /*---------------------------------------------------------------------------*/
276 /*
277  *  PROCEED HERE WHEN NO ERROR
278  */
279 /*---------------------------------------------------------------------------*/
280 #if defined(UPSAMPLE)
281 oldaudio = peasycap->oldaudio;
282 #endif /*UPSAMPLE*/
283
284 for (i = 0;  i < purb->number_of_packets; i++) {
285         switch (purb->iso_frame_desc[i].status) {
286         case  0: {
287                 break;
288         }
289         case -ENOENT: {
290                 SAM("-ENOENT\n");
291                 break;
292         }
293         case -EINPROGRESS: {
294                 SAM("-EINPROGRESS\n");
295                 break;
296         }
297         case -EPROTO: {
298                 SAM("-EPROTO\n");
299                 break;
300         }
301         case -EILSEQ: {
302                 SAM("-EILSEQ\n");
303                 break;
304         }
305         case -ETIME: {
306                 SAM("-ETIME\n");
307                 break;
308         }
309         case -ETIMEDOUT: {
310                 SAM("-ETIMEDOUT\n");
311                 break;
312         }
313         case -EPIPE: {
314                 SAM("-EPIPE\n");
315                 break;
316         }
317         case -ECOMM: {
318                 SAM("-ECOMM\n");
319                 break;
320         }
321         case -ENOSR: {
322                 SAM("-ENOSR\n");
323                 break;
324         }
325         case -EOVERFLOW: {
326                 SAM("-EOVERFLOW\n");
327                 break;
328         }
329         case -EREMOTEIO: {
330                 SAM("-EREMOTEIO\n");
331                 break;
332         }
333         case -ENODEV: {
334                 SAM("-ENODEV\n");
335                 break;
336         }
337         case -EXDEV: {
338                 SAM("-EXDEV\n");
339                 break;
340         }
341         case -EINVAL: {
342                 SAM("-EINVAL\n");
343                 break;
344         }
345         case -ECONNRESET: {
346                 SAM("-ECONNRESET\n");
347                 break;
348         }
349         case -ENOSPC: {
350                 SAM("-ENOSPC\n");
351                 break;
352         }
353         case -ESHUTDOWN: {
354                 SAM("-ESHUTDOWN\n");
355                 break;
356         }
357         default: {
358                 SAM("unknown error:0x%08X\n", purb->iso_frame_desc[i].status);
359                 break;
360         }
361         }
362         if (!purb->iso_frame_desc[i].status) {
363                 more = purb->iso_frame_desc[i].actual_length;
364
365 #if defined(TESTTONE)
366                 if (!more)
367                         more = purb->iso_frame_desc[i].length;
368 #endif
369
370                 if (!more)
371                         peasycap->audio_mt++;
372                 else {
373                         if (peasycap->audio_mt) {
374                                 JOM(16, "%4i empty audio urb frames\n", \
375                                                         peasycap->audio_mt);
376                                 peasycap->audio_mt = 0;
377                         }
378
379                         p1 = (__u8 *)(purb->transfer_buffer + \
380                                         purb->iso_frame_desc[i].offset);
381
382                         leap = 0;
383                         p1 += leap;
384                         more -= leap;
385 /*---------------------------------------------------------------------------*/
386 /*
387  *  COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
388  *  CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY
389  */
390 /*---------------------------------------------------------------------------*/
391                         while (more) {
392                                 if (0 > more) {
393                                         SAM("easysnd_complete: MISTAKE: " \
394                                                         "more is negative\n");
395                                         return;
396                                 }
397                                 if (peasycap->audio_buffer_page_many <= \
398                                                         peasycap->audio_fill) {
399                                         SAM("ERROR: bad " \
400                                                 "peasycap->audio_fill\n");
401                                         return;
402                                 }
403
404                                 paudio_buffer = &peasycap->audio_buffer\
405                                                         [peasycap->audio_fill];
406                                 if (PAGE_SIZE < (paudio_buffer->pto - \
407                                                 paudio_buffer->pgo)) {
408                                         SAM("ERROR: bad paudio_buffer->pto\n");
409                                         return;
410                                 }
411                                 if (PAGE_SIZE == (paudio_buffer->pto - \
412                                                         paudio_buffer->pgo)) {
413
414 #if defined(TESTTONE)
415                                         easysnd_testtone(peasycap, \
416                                                         peasycap->audio_fill);
417 #endif /*TESTTONE*/
418
419                                         paudio_buffer->pto = \
420                                                         paudio_buffer->pgo;
421                                         (peasycap->audio_fill)++;
422                                         if (peasycap->\
423                                                 audio_buffer_page_many <= \
424                                                         peasycap->audio_fill)
425                                                 peasycap->audio_fill = 0;
426
427                                         JOM(12, "bumped peasycap->" \
428                                                         "audio_fill to %i\n", \
429                                                         peasycap->audio_fill);
430
431                                         paudio_buffer = &peasycap->\
432                                                         audio_buffer\
433                                                         [peasycap->audio_fill];
434                                         paudio_buffer->pto = \
435                                                         paudio_buffer->pgo;
436
437                                         if (!(peasycap->audio_fill % \
438                                                 peasycap->\
439                                                 audio_pages_per_fragment)) {
440                                                 JOM(12, "wakeup call on wq_" \
441                                                 "audio, %i=frag reading  %i" \
442                                                 "=fragment fill\n", \
443                                                 (peasycap->audio_read / \
444                                                 peasycap->\
445                                                 audio_pages_per_fragment), \
446                                                 (peasycap->audio_fill / \
447                                                 peasycap->\
448                                                 audio_pages_per_fragment));
449                                                 wake_up_interruptible\
450                                                 (&(peasycap->wq_audio));
451                                         }
452                                 }
453
454                                 much = PAGE_SIZE - (int)(paudio_buffer->pto -\
455                                                          paudio_buffer->pgo);
456
457                                 if (false == peasycap->microphone) {
458                                         if (much > more)
459                                                 much = more;
460
461                                         memcpy(paudio_buffer->pto, p1, much);
462                                         p1 += much;
463                                         more -= much;
464                                 } else {
465 #if defined(UPSAMPLE)
466                                         if (much % 16)
467                                                 JOM(8, "MISTAKE? much" \
468                                                 " is not divisible by 16\n");
469                                         if (much > (16 * \
470                                                         more))
471                                                 much = 16 * \
472                                                         more;
473                                         p2 = (__u8 *)paudio_buffer->pto;
474
475                                         for (j = 0;  j < (much/16);  j++) {
476                                                 newaudio =  ((int) *p1) - 128;
477                                                 newaudio = 128 * \
478                                                                 newaudio;
479
480                                                 delta = (newaudio - oldaudio) \
481                                                                         / 4;
482                                                 s16 = oldaudio + delta;
483
484                                                 for (k = 0;  k < 4;  k++) {
485                                                         *p2 = (0x00FF & s16);
486                                                         *(p2 + 1) = (0xFF00 & \
487                                                                 s16) >> 8;
488                                                         p2 += 2;
489                                                         *p2 = (0x00FF & s16);
490                                                         *(p2 + 1) = (0xFF00 & \
491                                                                 s16) >> 8;
492                                                         p2 += 2;
493
494                                                         s16 += delta;
495                                                 }
496                                                 p1++;
497                                                 more--;
498                                                 oldaudio = s16;
499                                         }
500 #else
501                                         if (much > (2 * more))
502                                                 much = 2 * more;
503                                         p2 = (__u8 *)paudio_buffer->pto;
504
505                                         for (j = 0;  j < (much / 2);  j++) {
506                                                 s16 =  ((int) *p1) - 128;
507                                                 s16 = 128 * \
508                                                                 s16;
509                                                 *p2 = (0x00FF & s16);
510                                                 *(p2 + 1) = (0xFF00 & s16) >> \
511                                                                         8;
512                                                 p1++;  p2 += 2;
513                                                 more--;
514                                         }
515 #endif /*UPSAMPLE*/
516                                 }
517                                 (paudio_buffer->pto) += much;
518                         }
519                 }
520         } else {
521                 JOM(12, "discarding audio samples because " \
522                         "%i=purb->iso_frame_desc[i].status\n", \
523                                 purb->iso_frame_desc[i].status);
524         }
525
526 #if defined(UPSAMPLE)
527 peasycap->oldaudio = oldaudio;
528 #endif /*UPSAMPLE*/
529
530 }
531 /*---------------------------------------------------------------------------*/
532 /*
533  *  RESUBMIT THIS URB AFTER NO ERROR
534  */
535 /*---------------------------------------------------------------------------*/
536 if (peasycap->audio_isoc_streaming) {
537         rc = usb_submit_urb(purb, GFP_ATOMIC);
538         if (0 != rc) {
539                 if (-ENODEV != rc) {
540                         SAM("ERROR: while %i=audio_idle, " \
541                                         "usb_submit_urb() failed " \
542                                         "with rc:\n", peasycap->audio_idle);
543                 }
544                 switch (rc) {
545                 case -ENOMEM: {
546                         SAM("-ENOMEM\n");
547                         break;
548                 }
549                 case -ENODEV: {
550                         break;
551                 }
552                 case -ENXIO: {
553                         SAM("-ENXIO\n");
554                         break;
555                 }
556                 case -EINVAL: {
557                         SAM("-EINVAL\n");
558                         break;
559                 }
560                 case -EAGAIN: {
561                         SAM("-EAGAIN\n");
562                         break;
563                 }
564                 case -EFBIG: {
565                         SAM("-EFBIG\n");
566                         break;
567                 }
568                 case -EPIPE: {
569                         SAM("-EPIPE\n");
570                         break;
571                 }
572                 case -EMSGSIZE: {
573                         SAM("-EMSGSIZE\n");
574                         break;
575                 }
576                 case -ENOSPC: {
577                         SAM("-ENOSPC\n");
578                         break;
579                 }
580                 default: {
581                         SAM("unknown error: 0x%08X\n", rc);
582                         break;
583                 }
584                 }
585         }
586 }
587 return;
588 }
589 /*****************************************************************************/
590 /*---------------------------------------------------------------------------*/
591 /*
592  *  THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
593  *  STREAM FROM /dev/easysnd1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
594  *  HAVE AN IOCTL INTERFACE.
595  */
596 /*---------------------------------------------------------------------------*/
597 int
598 easysnd_open(struct inode *inode, struct file *file)
599 {
600 struct usb_interface *pusb_interface;
601 struct easycap *peasycap;
602 int subminor, rc;
603 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
604 #if defined(EASYCAP_IS_VIDEODEV_CLIENT)
605 #if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
606 struct v4l2_device *pv4l2_device;
607 #endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
608 #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
609 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
610
611 JOT(4, "begins\n");
612
613 subminor = iminor(inode);
614
615 pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
616 if (NULL == pusb_interface) {
617         SAY("ERROR: pusb_interface is NULL\n");
618         SAY("ending unsuccessfully\n");
619         return -1;
620 }
621 peasycap = usb_get_intfdata(pusb_interface);
622 if (NULL == peasycap) {
623         SAY("ERROR: peasycap is NULL\n");
624         SAY("ending unsuccessfully\n");
625         return -1;
626 }
627 /*---------------------------------------------------------------------------*/
628 #if (!defined(EASYCAP_IS_VIDEODEV_CLIENT))
629 #
630 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
631 #else
632 #if defined(EASYCAP_NEEDS_V4L2_DEVICE_H)
633 /*---------------------------------------------------------------------------*/
634 /*
635  *  SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
636  *  BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
637  *  REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
638  *  TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
639 */
640 /*---------------------------------------------------------------------------*/
641 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
642         pv4l2_device = usb_get_intfdata(pusb_interface);
643         if ((struct v4l2_device *)NULL == pv4l2_device) {
644                 SAY("ERROR: pv4l2_device is NULL\n");
645                 return -EFAULT;
646         }
647         peasycap = (struct easycap *) \
648                 container_of(pv4l2_device, struct easycap, v4l2_device);
649 }
650 #endif /*EASYCAP_NEEDS_V4L2_DEVICE_H*/
651 #
652 #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
653 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
654 /*---------------------------------------------------------------------------*/
655 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
656         SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
657         return -EFAULT;
658 }
659 /*---------------------------------------------------------------------------*/
660
661 file->private_data = peasycap;
662
663 /*---------------------------------------------------------------------------*/
664 /*
665  *  INITIALIZATION
666  */
667 /*---------------------------------------------------------------------------*/
668 JOM(4, "starting initialization\n");
669
670 if ((struct usb_device *)NULL == peasycap->pusb_device) {
671         SAM("ERROR: peasycap->pusb_device is NULL\n");
672         return -ENODEV;
673 }
674 JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
675
676 rc = audio_setup(peasycap);
677 if (0 <= rc)
678         JOM(8, "audio_setup() returned %i\n", rc);
679 else
680         JOM(8, "easysnd open(): ERROR: audio_setup() returned %i\n", rc);
681
682 if ((struct usb_device *)NULL == peasycap->pusb_device) {
683         SAM("ERROR: peasycap->pusb_device has become NULL\n");
684         return -ENODEV;
685 }
686 /*---------------------------------------------------------------------------*/
687 if ((struct usb_device *)NULL == peasycap->pusb_device) {
688         SAM("ERROR: peasycap->pusb_device has become NULL\n");
689         return -ENODEV;
690 }
691 rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface, \
692                                         peasycap->audio_altsetting_on);
693 JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface, \
694                                         peasycap->audio_altsetting_on, rc);
695
696 rc = wakeup_device(peasycap->pusb_device);
697 if (0 == rc)
698         JOM(8, "wakeup_device() returned %i\n", rc);
699 else
700         JOM(8, "ERROR: wakeup_device() returned %i\n", rc);
701
702 peasycap->audio_eof = 0;
703 peasycap->audio_idle = 0;
704
705 peasycap->timeval1.tv_sec  = 0;
706 peasycap->timeval1.tv_usec = 0;
707
708 submit_audio_urbs(peasycap);
709
710 JOM(4, "finished initialization\n");
711 return 0;
712 }
713 /*****************************************************************************/
714 int
715 easysnd_release(struct inode *inode, struct file *file)
716 {
717 struct easycap *peasycap;
718
719 JOT(4, "begins\n");
720
721 peasycap = file->private_data;
722 if (NULL == peasycap) {
723         SAY("ERROR:  peasycap is NULL.\n");
724         return -EFAULT;
725 }
726 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
727         SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
728         return -EFAULT;
729 }
730 if (0 != kill_audio_urbs(peasycap)) {
731         SAM("ERROR: kill_audio_urbs() failed\n");
732         return -EFAULT;
733 }
734 JOM(4, "ending successfully\n");
735 return 0;
736 }
737 /*****************************************************************************/
738 ssize_t
739 easysnd_read(struct file *file, char __user *puserspacebuffer, \
740                                                 size_t kount, loff_t *poff)
741 {
742 struct timeval timeval;
743 long long int above, below, mean;
744 struct signed_div_result sdr;
745 unsigned char *p0;
746 long int kount1, more, rc, l0, lm;
747 int fragment, kd;
748 struct easycap *peasycap;
749 struct data_buffer *pdata_buffer;
750 size_t szret;
751
752 /*---------------------------------------------------------------------------*/
753 /*
754  *  DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
755  *
756  ******************************************************************************
757  *****  N.B.  IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
758  *****        THIS CONDITION SIGNIFIES END-OF-FILE.                      ******
759  ******************************************************************************
760  */
761 /*---------------------------------------------------------------------------*/
762
763 JOT(8, "===== easysnd_read(): kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
764
765 if (NULL == file) {
766         SAY("ERROR:  file is NULL\n");
767         return -ERESTARTSYS;
768 }
769 peasycap = file->private_data;
770 if (NULL == peasycap) {
771         SAY("ERROR in easysnd_read(): peasycap is NULL\n");
772         return -EFAULT;
773 }
774 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
775         SAY("ERROR: bad peasycap: 0x%08lX\n", (unsigned long int) peasycap);
776         return -EFAULT;
777 }
778 if (NULL == peasycap->pusb_device) {
779         SAY("ERROR in easysnd_read(): peasycap->pusb_device is NULL\n");
780         return -EFAULT;
781 }
782 kd = isdongle(peasycap);
783 if (0 <= kd && DONGLE_MANY > kd) {
784         if (mutex_lock_interruptible(&(easycap_dongle[kd].mutex_audio))) {
785                 SAY("ERROR: cannot lock easycap_dongle[%i].mutex_audio\n", kd);
786                 return -ERESTARTSYS;
787         }
788         JOM(4, "locked easycap_dongle[%i].mutex_audio\n", kd);
789 /*---------------------------------------------------------------------------*/
790 /*
791  *  MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
792  *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
793  *  IF NECESSARY, BAIL OUT.
794 */
795 /*---------------------------------------------------------------------------*/
796         if (kd != isdongle(peasycap))
797                 return -ERESTARTSYS;
798         if (NULL == file) {
799                 SAY("ERROR:  file is NULL\n");
800                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
801                 return -ERESTARTSYS;
802         }
803         peasycap = file->private_data;
804         if (NULL == peasycap) {
805                 SAY("ERROR:  peasycap is NULL\n");
806                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
807                 return -ERESTARTSYS;
808         }
809         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
810                 SAY("ERROR: bad peasycap: 0x%08lX\n", \
811                                                 (unsigned long int) peasycap);
812                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
813                 return -ERESTARTSYS;
814         }
815         if (NULL == peasycap->pusb_device) {
816                 SAM("ERROR: peasycap->pusb_device is NULL\n");
817                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
818                 return -ERESTARTSYS;
819         }
820 } else {
821 /*---------------------------------------------------------------------------*/
822 /*
823  *  IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
824  *  ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED.  BAIL OUT.
825 */
826 /*---------------------------------------------------------------------------*/
827         return -ERESTARTSYS;
828 }
829 /*---------------------------------------------------------------------------*/
830 if (file->f_flags & O_NONBLOCK)
831         JOT(16, "NONBLOCK  kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
832 else
833         JOT(8, "BLOCKING  kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
834
835 if ((0 > peasycap->audio_read) || \
836                 (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
837         SAM("ERROR: peasycap->audio_read out of range\n");
838         mutex_unlock(&easycap_dongle[kd].mutex_audio);
839         return -EFAULT;
840 }
841 pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
842 if ((struct data_buffer *)NULL == pdata_buffer) {
843         SAM("ERROR: pdata_buffer is NULL\n");
844         mutex_unlock(&easycap_dongle[kd].mutex_audio);
845         return -EFAULT;
846 }
847 JOM(12, "before wait, %i=frag read  %i=frag fill\n", \
848                 (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
849                 (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
850 fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
851 while ((fragment == (peasycap->audio_fill / \
852                                 peasycap->audio_pages_per_fragment)) || \
853                 (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
854         if (file->f_flags & O_NONBLOCK) {
855                 JOM(16, "returning -EAGAIN as instructed\n");
856                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
857                 return -EAGAIN;
858         }
859         rc = wait_event_interruptible(peasycap->wq_audio, \
860                 (peasycap->audio_idle  || peasycap->audio_eof   || \
861                 ((fragment != (peasycap->audio_fill / \
862                                 peasycap->audio_pages_per_fragment)) && \
863                 (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
864         if (0 != rc) {
865                 SAM("aborted by signal\n");
866                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
867                 return -ERESTARTSYS;
868         }
869         if (peasycap->audio_eof) {
870                 JOM(8, "returning 0 because  %i=audio_eof\n", \
871                                                         peasycap->audio_eof);
872                 kill_audio_urbs(peasycap);
873                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
874                 return 0;
875         }
876         if (peasycap->audio_idle) {
877                 JOM(16, "returning 0 because  %i=audio_idle\n", \
878                                                         peasycap->audio_idle);
879                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
880                 return 0;
881         }
882         if (!peasycap->audio_isoc_streaming) {
883                 JOM(16, "returning 0 because audio urbs not streaming\n");
884                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
885                 return 0;
886         }
887 }
888 JOM(12, "after  wait, %i=frag read  %i=frag fill\n", \
889                 (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
890                 (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
891 szret = (size_t)0;
892 while (fragment == (peasycap->audio_read / \
893                                 peasycap->audio_pages_per_fragment)) {
894         if (NULL == pdata_buffer->pgo) {
895                 SAM("ERROR: pdata_buffer->pgo is NULL\n");
896                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
897                 return -EFAULT;
898         }
899         if (NULL == pdata_buffer->pto) {
900                 SAM("ERROR: pdata_buffer->pto is NULL\n");
901                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
902                 return -EFAULT;
903         }
904         kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
905         if (0 > kount1) {
906                 SAM("easysnd_read: MISTAKE: kount1 is negative\n");
907                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
908                 return -ERESTARTSYS;
909         }
910         if (!kount1) {
911                 (peasycap->audio_read)++;
912                 if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
913                         peasycap->audio_read = 0;
914                 JOM(12, "bumped peasycap->audio_read to %i\n", \
915                                                 peasycap->audio_read);
916
917                 if (fragment != (peasycap->audio_read / \
918                                         peasycap->audio_pages_per_fragment))
919                         break;
920
921                 if ((0 > peasycap->audio_read) || \
922                         (peasycap->audio_buffer_page_many <= \
923                                         peasycap->audio_read)) {
924                         SAM("ERROR: peasycap->audio_read out of range\n");
925                         mutex_unlock(&easycap_dongle[kd].mutex_audio);
926                         return -EFAULT;
927                 }
928                 pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
929                 if ((struct data_buffer *)NULL == pdata_buffer) {
930                         SAM("ERROR: pdata_buffer is NULL\n");
931                         mutex_unlock(&easycap_dongle[kd].mutex_audio);
932                         return -EFAULT;
933                 }
934                 if (NULL == pdata_buffer->pgo) {
935                         SAM("ERROR: pdata_buffer->pgo is NULL\n");
936                         mutex_unlock(&easycap_dongle[kd].mutex_audio);
937                         return -EFAULT;
938                 }
939                 if (NULL == pdata_buffer->pto) {
940                         SAM("ERROR: pdata_buffer->pto is NULL\n");
941                         mutex_unlock(&easycap_dongle[kd].mutex_audio);
942                         return -EFAULT;
943                 }
944                 kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
945         }
946         JOM(12, "ready  to send %li bytes\n", (long int) kount1);
947         JOM(12, "still  to send %li bytes\n", (long int) kount);
948         more = kount1;
949         if (more > kount)
950                 more = kount;
951         JOM(12, "agreed to send %li bytes from page %i\n", \
952                                                 more, peasycap->audio_read);
953         if (!more)
954                 break;
955
956 /*---------------------------------------------------------------------------*/
957 /*
958  *  ACCUMULATE DYNAMIC-RANGE INFORMATION
959  */
960 /*---------------------------------------------------------------------------*/
961         p0 = (unsigned char *)pdata_buffer->pgo;  l0 = 0;  lm = more/2;
962         while (l0 < lm) {
963                 SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau, \
964                                 &peasycap->audio_square);  l0++;  p0 += 2;
965         }
966 /*---------------------------------------------------------------------------*/
967         rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
968         if (0 != rc) {
969                 SAM("ERROR: copy_to_user() returned %li\n", rc);
970                 mutex_unlock(&easycap_dongle[kd].mutex_audio);
971                 return -EFAULT;
972         }
973         *poff += (loff_t)more;
974         szret += (size_t)more;
975         pdata_buffer->pto += more;
976         puserspacebuffer += more;
977         kount -= (size_t)more;
978 }
979 JOM(12, "after  read, %i=frag read  %i=frag fill\n", \
980                 (peasycap->audio_read / peasycap->audio_pages_per_fragment), \
981                 (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
982 if (kount < 0) {
983         SAM("MISTAKE:  %li=kount  %li=szret\n", \
984                                         (long int)kount, (long int)szret);
985 }
986 /*---------------------------------------------------------------------------*/
987 /*
988  *  CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
989  */
990 /*---------------------------------------------------------------------------*/
991 if (peasycap->audio_sample) {
992         below = peasycap->audio_sample;
993         above = peasycap->audio_square;
994         sdr = signed_div(above, below);
995         above = sdr.quotient;
996         mean = peasycap->audio_niveau;
997         sdr = signed_div(mean, peasycap->audio_sample);
998
999         JOM(8, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n", \
1000                                 sdr.quotient, above, peasycap->audio_sample);
1001
1002         sdr = signed_div(above, 32768);
1003         JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
1004 }
1005 /*---------------------------------------------------------------------------*/
1006 /*
1007  *  UPDATE THE AUDIO CLOCK
1008  */
1009 /*---------------------------------------------------------------------------*/
1010 do_gettimeofday(&timeval);
1011 if (!peasycap->timeval1.tv_sec) {
1012         peasycap->audio_bytes = 0;
1013         peasycap->timeval3 = timeval;
1014         peasycap->timeval1 = peasycap->timeval3;
1015         sdr.quotient = 192000;
1016 } else {
1017         peasycap->audio_bytes += (long long int) szret;
1018         below = ((long long int)(1000000)) * \
1019                 ((long long int)(timeval.tv_sec  - \
1020                                                 peasycap->timeval3.tv_sec)) + \
1021                 (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec);
1022         above = 1000000 * ((long long int) peasycap->audio_bytes);
1023
1024         if (below)
1025                 sdr = signed_div(above, below);
1026         else
1027                 sdr.quotient = 192000;
1028 }
1029 JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
1030 peasycap->dnbydt = sdr.quotient;
1031
1032 JOM(8, "returning %li\n", (long int)szret);
1033 mutex_unlock(&easycap_dongle[kd].mutex_audio);
1034 return szret;
1035 }
1036 /*****************************************************************************/
1037 /*---------------------------------------------------------------------------*/
1038 /*
1039  *  SUBMIT ALL AUDIO URBS.
1040  */
1041 /*---------------------------------------------------------------------------*/
1042 int
1043 submit_audio_urbs(struct easycap *peasycap)
1044 {
1045 struct data_urb *pdata_urb;
1046 struct urb *purb;
1047 struct list_head *plist_head;
1048 int j, isbad, nospc, m, rc;
1049 int isbuf;
1050
1051 if (NULL == peasycap) {
1052         SAY("ERROR: peasycap is NULL\n");
1053         return -EFAULT;
1054 }
1055 if ((struct list_head *)NULL == peasycap->purb_audio_head) {
1056         SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
1057         return -EFAULT;
1058 }
1059 if ((struct usb_device *)NULL == peasycap->pusb_device) {
1060         SAM("ERROR: peasycap->pusb_device is NULL\n");
1061         return -EFAULT;
1062 }
1063 if (!peasycap->audio_isoc_streaming) {
1064         JOM(4, "initial submission of all audio urbs\n");
1065         rc = usb_set_interface(peasycap->pusb_device,
1066                                         peasycap->audio_interface, \
1067                                         peasycap->audio_altsetting_on);
1068         JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", \
1069                                         peasycap->audio_interface, \
1070                                         peasycap->audio_altsetting_on, rc);
1071
1072         isbad = 0;  nospc = 0;  m = 0;
1073         list_for_each(plist_head, (peasycap->purb_audio_head)) {
1074                 pdata_urb = list_entry(plist_head, struct data_urb, list_head);
1075                 if (NULL != pdata_urb) {
1076                         purb = pdata_urb->purb;
1077                         if (NULL != purb) {
1078                                 isbuf = pdata_urb->isbuf;
1079
1080                                 purb->interval = 1;
1081                                 purb->dev = peasycap->pusb_device;
1082                                 purb->pipe = \
1083                                         usb_rcvisocpipe(peasycap->pusb_device,\
1084                                         peasycap->audio_endpointnumber);
1085                                 purb->transfer_flags = URB_ISO_ASAP;
1086                                 purb->transfer_buffer = \
1087                                         peasycap->audio_isoc_buffer[isbuf].pgo;
1088                                 purb->transfer_buffer_length = \
1089                                         peasycap->audio_isoc_buffer_size;
1090                                 purb->complete = easysnd_complete;
1091                                 purb->context = peasycap;
1092                                 purb->start_frame = 0;
1093                                 purb->number_of_packets = \
1094                                         peasycap->audio_isoc_framesperdesc;
1095                                 for (j = 0;  j < peasycap->\
1096                                                 audio_isoc_framesperdesc; \
1097                                                                         j++) {
1098                                         purb->iso_frame_desc[j].offset = j * \
1099                                                 peasycap->\
1100                                                 audio_isoc_maxframesize;
1101                                         purb->iso_frame_desc[j].length = \
1102                                                 peasycap->\
1103                                                 audio_isoc_maxframesize;
1104                                 }
1105
1106                                 rc = usb_submit_urb(purb, GFP_KERNEL);
1107                                 if (0 != rc) {
1108                                         isbad++;
1109                                         SAM("ERROR: usb_submit_urb() failed" \
1110                                                         " for urb with rc:\n");
1111                                         switch (rc) {
1112                                         case -ENOMEM: {
1113                                                 SAM("-ENOMEM\n");
1114                                                 break;
1115                                         }
1116                                         case -ENODEV: {
1117                                                 SAM("-ENODEV\n");
1118                                                 break;
1119                                         }
1120                                         case -ENXIO: {
1121                                                 SAM("-ENXIO\n");
1122                                                 break;
1123                                         }
1124                                         case -EINVAL: {
1125                                                 SAM("-EINVAL\n");
1126                                                 break;
1127                                         }
1128                                         case -EAGAIN: {
1129                                                 SAM("-EAGAIN\n");
1130                                                 break;
1131                                         }
1132                                         case -EFBIG: {
1133                                                 SAM("-EFBIG\n");
1134                                                 break;
1135                                         }
1136                                         case -EPIPE: {
1137                                                 SAM("-EPIPE\n");
1138                                                 break;
1139                                         }
1140                                         case -EMSGSIZE: {
1141                                                 SAM("-EMSGSIZE\n");
1142                                                 break;
1143                                         }
1144                                         case -ENOSPC: {
1145                                                 nospc++;
1146                                                 break;
1147                                         }
1148                                         default: {
1149                                                 SAM("unknown error code %i\n",\
1150                                                                  rc);
1151                                                 break;
1152                                         }
1153                                         }
1154                                 } else {
1155                                          m++;
1156                                 }
1157                         } else {
1158                                 isbad++;
1159                         }
1160                 } else {
1161                         isbad++;
1162                 }
1163         }
1164         if (nospc) {
1165                 SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
1166                 SAM(".....  possibly inadequate USB bandwidth\n");
1167                 peasycap->audio_eof = 1;
1168         }
1169         if (isbad) {
1170                 JOM(4, "attempting cleanup instead of submitting\n");
1171                 list_for_each(plist_head, (peasycap->purb_audio_head)) {
1172                         pdata_urb = list_entry(plist_head, struct data_urb, \
1173                                                                 list_head);
1174                         if (NULL != pdata_urb) {
1175                                 purb = pdata_urb->purb;
1176                                 if (NULL != purb)
1177                                         usb_kill_urb(purb);
1178                         }
1179                 }
1180                 peasycap->audio_isoc_streaming = 0;
1181         } else {
1182                 peasycap->audio_isoc_streaming = 1;
1183                 JOM(4, "submitted %i audio urbs\n", m);
1184         }
1185 } else
1186         JOM(4, "already streaming audio urbs\n");
1187
1188 return 0;
1189 }
1190 /*****************************************************************************/
1191 /*---------------------------------------------------------------------------*/
1192 /*
1193  *  KILL ALL AUDIO URBS.
1194  */
1195 /*---------------------------------------------------------------------------*/
1196 int
1197 kill_audio_urbs(struct easycap *peasycap)
1198 {
1199 int m;
1200 struct list_head *plist_head;
1201 struct data_urb *pdata_urb;
1202
1203 if (NULL == peasycap) {
1204         SAY("ERROR: peasycap is NULL\n");
1205         return -EFAULT;
1206 }
1207 if (peasycap->audio_isoc_streaming) {
1208         if ((struct list_head *)NULL != peasycap->purb_audio_head) {
1209                 peasycap->audio_isoc_streaming = 0;
1210                 JOM(4, "killing audio urbs\n");
1211                 m = 0;
1212                 list_for_each(plist_head, (peasycap->purb_audio_head)) {
1213                         pdata_urb = list_entry(plist_head, struct data_urb,
1214                                                                 list_head);
1215                         if ((struct data_urb *)NULL != pdata_urb) {
1216                                 if ((struct urb *)NULL != pdata_urb->purb) {
1217                                         usb_kill_urb(pdata_urb->purb);
1218                                         m++;
1219                                 }
1220                         }
1221                 }
1222                 JOM(4, "%i audio urbs killed\n", m);
1223         } else {
1224                 SAM("ERROR: peasycap->purb_audio_head is NULL\n");
1225                 return -EFAULT;
1226         }
1227 } else {
1228         JOM(8, "%i=audio_isoc_streaming, no audio urbs killed\n", \
1229                                         peasycap->audio_isoc_streaming);
1230 }
1231 return 0;
1232 }
1233 /*****************************************************************************/