Merge branch 'for-paul' of git://gitorious.org/linux-omap-dss2/linux
[pandora-kernel.git] / drivers / staging / easycap / easycap_sound_oss.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
33 /*****************************************************************************/
34 /****************************                       **************************/
35 /****************************   Open Sound System   **************************/
36 /****************************                       **************************/
37 /*****************************************************************************/
38 /*--------------------------------------------------------------------------*/
39 /*
40  *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
41  */
42 /*--------------------------------------------------------------------------*/
43 /*****************************************************************************/
44 /*---------------------------------------------------------------------------*/
45 /*
46  *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
47  *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
48  *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
49  */
50 /*---------------------------------------------------------------------------*/
51 void
52 easyoss_complete(struct urb *purb)
53 {
54         struct easycap *peasycap;
55         struct data_buffer *paudio_buffer;
56         u8 *p1, *p2;
57         s16 tmp;
58         int i, j, more, much, leap, rc;
59 #ifdef UPSAMPLE
60         int k;
61         s16 oldaudio, newaudio, delta;
62 #endif /*UPSAMPLE*/
63
64         JOT(16, "\n");
65
66         if (!purb) {
67                 SAY("ERROR: purb is NULL\n");
68                 return;
69         }
70         peasycap = purb->context;
71         if (!peasycap) {
72                 SAY("ERROR: peasycap is NULL\n");
73                 return;
74         }
75         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
76                 SAY("ERROR: bad peasycap\n");
77                 return;
78         }
79         much = 0;
80         if (peasycap->audio_idle) {
81                 JOM(16, "%i=audio_idle  %i=audio_isoc_streaming\n",
82                     peasycap->audio_idle, peasycap->audio_isoc_streaming);
83                 if (peasycap->audio_isoc_streaming) {
84                         rc = usb_submit_urb(purb, GFP_ATOMIC);
85                         if (rc) {
86                                 if (-ENODEV != rc && -ENOENT != rc) {
87                                         SAM("ERROR: while %i=audio_idle, "
88                                             "usb_submit_urb() failed with rc: -%s: %d\n",
89                                             peasycap->audio_idle,
90                                             strerror(rc), rc);
91                                 }
92                         }
93                 }
94                 return;
95         }
96 /*---------------------------------------------------------------------------*/
97         if (purb->status) {
98                 if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
99                         JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
100                         return;
101                 }
102                 SAM("ERROR: non-zero urb status: -%s: %d\n",
103                     strerror(purb->status), purb->status);
104                 goto resubmit;
105         }
106 /*---------------------------------------------------------------------------*/
107 /*
108  *  PROCEED HERE WHEN NO ERROR
109  */
110 /*---------------------------------------------------------------------------*/
111 #ifdef UPSAMPLE
112         oldaudio = peasycap->oldaudio;
113 #endif /*UPSAMPLE*/
114
115         for (i = 0;  i < purb->number_of_packets; i++) {
116                 if (!purb->iso_frame_desc[i].status) {
117
118                         SAM("-%s\n", strerror(purb->iso_frame_desc[i].status));
119
120                         more = purb->iso_frame_desc[i].actual_length;
121
122                         if (!more)
123                                 peasycap->audio_mt++;
124                         else {
125                                 if (peasycap->audio_mt) {
126                                         JOM(12, "%4i empty audio urb frames\n",
127                                             peasycap->audio_mt);
128                                         peasycap->audio_mt = 0;
129                                 }
130
131                                 p1 = (u8 *)(purb->transfer_buffer + purb->iso_frame_desc[i].offset);
132
133                                 leap = 0;
134                                 p1 += leap;
135                                 more -= leap;
136                                 /*
137                                  *  COPY more BYTES FROM ISOC BUFFER
138                                  *  TO AUDIO BUFFER, CONVERTING
139                                  *  8-BIT MONO TO 16-BIT SIGNED
140                                  *  LITTLE-ENDIAN SAMPLES IF NECESSARY
141                                  */
142                                 while (more) {
143                                         if (0 > more) {
144                                                 SAM("MISTAKE: more is negative\n");
145                                                 return;
146                                         }
147                                         if (peasycap->audio_buffer_page_many <= peasycap->audio_fill) {
148                                                 SAM("ERROR: bad peasycap->audio_fill\n");
149                                                 return;
150                                         }
151
152                                         paudio_buffer = &peasycap->audio_buffer[peasycap->audio_fill];
153                                         if (PAGE_SIZE < (paudio_buffer->pto - paudio_buffer->pgo)) {
154                                                 SAM("ERROR: bad paudio_buffer->pto\n");
155                                                 return;
156                                         }
157                                         if (PAGE_SIZE == (paudio_buffer->pto - paudio_buffer->pgo)) {
158
159                                                 paudio_buffer->pto = paudio_buffer->pgo;
160                                                 (peasycap->audio_fill)++;
161                                                 if (peasycap->audio_buffer_page_many <= peasycap->audio_fill)
162                                                         peasycap->audio_fill = 0;
163
164                                                 JOM(8, "bumped peasycap->"
165                                                     "audio_fill to %i\n",
166                                                     peasycap->audio_fill);
167
168                                                 paudio_buffer = &peasycap->audio_buffer[peasycap->audio_fill];
169                                                 paudio_buffer->pto = paudio_buffer->pgo;
170
171                                                 if (!(peasycap->audio_fill % peasycap->audio_pages_per_fragment)) {
172                                                         JOM(12, "wakeup call on wq_audio, %i=frag reading  %i=fragment fill\n",
173                                                             (peasycap->audio_read / peasycap->audio_pages_per_fragment),
174                                                             (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
175                                                         wake_up_interruptible(&(peasycap->wq_audio));
176                                                 }
177                                         }
178
179                                         much = PAGE_SIZE - (int)(paudio_buffer->pto - paudio_buffer->pgo);
180
181                                         if (!peasycap->microphone) {
182                                                 if (much > more)
183                                                         much = more;
184
185                                                 memcpy(paudio_buffer->pto, p1, much);
186                                                 p1 += much;
187                                                 more -= much;
188                                         } else {
189 #ifdef UPSAMPLE
190                                                 if (much % 16)
191                                                         JOM(8, "MISTAKE? much"
192                                                             " is not divisible by 16\n");
193                                                 if (much > (16 * more))
194                                                         much = 16 * more;
195                                                 p2 = (u8 *)paudio_buffer->pto;
196
197                                                 for (j = 0;  j < (much/16);  j++) {
198                                                         newaudio =  ((int) *p1) - 128;
199                                                         newaudio = 128 * newaudio;
200
201                                                         delta = (newaudio - oldaudio) / 4;
202                                                         tmp = oldaudio + delta;
203
204                                                         for (k = 0;  k < 4;  k++) {
205                                                                 *p2 = (0x00FF & tmp);
206                                                                 *(p2 + 1) = (0xFF00 & tmp) >> 8;
207                                                                 p2 += 2;
208                                                                 *p2 = (0x00FF & tmp);
209                                                                 *(p2 + 1) = (0xFF00 & tmp) >> 8;
210                                                                 p2 += 2;
211
212                                                                 tmp += delta;
213                                                         }
214                                                         p1++;
215                                                         more--;
216                                                         oldaudio = tmp;
217                                                 }
218 #else /*!UPSAMPLE*/
219                                                 if (much > (2 * more))
220                                                         much = 2 * more;
221                                                 p2 = (u8 *)paudio_buffer->pto;
222
223                                                 for (j = 0;  j < (much / 2);  j++) {
224                                                         tmp =  ((int) *p1) - 128;
225                                                         tmp = 128 * tmp;
226                                                         *p2 = (0x00FF & tmp);
227                                                         *(p2 + 1) = (0xFF00 & tmp) >> 8;
228                                                         p1++;
229                                                         p2 += 2;
230                                                         more--;
231                                                 }
232 #endif /*UPSAMPLE*/
233                                         }
234                                         (paudio_buffer->pto) += much;
235                                 }
236                         }
237                 } else {
238                         JOM(12, "discarding audio samples because "
239                             "%i=purb->iso_frame_desc[i].status\n",
240                             purb->iso_frame_desc[i].status);
241                 }
242
243 #ifdef UPSAMPLE
244                 peasycap->oldaudio = oldaudio;
245 #endif /*UPSAMPLE*/
246
247         }
248 /*---------------------------------------------------------------------------*/
249 /*
250  *  RESUBMIT THIS URB
251  */
252 /*---------------------------------------------------------------------------*/
253 resubmit:
254         if (peasycap->audio_isoc_streaming) {
255                 rc = usb_submit_urb(purb, GFP_ATOMIC);
256                 if (rc) {
257                         if (-ENODEV != rc && -ENOENT != rc) {
258                                 SAM("ERROR: while %i=audio_idle, "
259                                     "usb_submit_urb() failed "
260                                     "with rc: -%s: %d\n", peasycap->audio_idle,
261                                     strerror(rc), rc);
262                         }
263                 }
264         }
265         return;
266 }
267 /*****************************************************************************/
268 /*---------------------------------------------------------------------------*/
269 /*
270  *  THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
271  *  STREAM FROM /dev/easyoss1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
272  *  HAVE AN IOCTL INTERFACE.
273  */
274 /*---------------------------------------------------------------------------*/
275 static int easyoss_open(struct inode *inode, struct file *file)
276 {
277         struct usb_interface *pusb_interface;
278         struct easycap *peasycap;
279         int subminor;
280         struct v4l2_device *pv4l2_device;
281
282         JOT(4, "begins\n");
283
284         subminor = iminor(inode);
285
286         pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
287         if (!pusb_interface) {
288                 SAY("ERROR: pusb_interface is NULL\n");
289                 SAY("ending unsuccessfully\n");
290                 return -1;
291         }
292         peasycap = usb_get_intfdata(pusb_interface);
293         if (!peasycap) {
294                 SAY("ERROR: peasycap is NULL\n");
295                 SAY("ending unsuccessfully\n");
296                 return -1;
297         }
298 /*---------------------------------------------------------------------------*/
299 /*
300  *  SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
301  *  BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
302  *  REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
303  *  TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
304 */
305 /*---------------------------------------------------------------------------*/
306         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
307                 pv4l2_device = usb_get_intfdata(pusb_interface);
308                 if (!pv4l2_device) {
309                         SAY("ERROR: pv4l2_device is NULL\n");
310                         return -EFAULT;
311                 }
312                 peasycap = container_of(pv4l2_device,
313                                 struct easycap, v4l2_device);
314         }
315 /*---------------------------------------------------------------------------*/
316         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
317                 SAY("ERROR: bad peasycap: %p\n", peasycap);
318                 return -EFAULT;
319         }
320 /*---------------------------------------------------------------------------*/
321
322         file->private_data = peasycap;
323
324         if (0 != easycap_sound_setup(peasycap)) {
325                 ;
326                 ;
327         }
328         return 0;
329 }
330 /*****************************************************************************/
331 static int easyoss_release(struct inode *inode, struct file *file)
332 {
333         struct easycap *peasycap;
334
335         JOT(4, "begins\n");
336
337         peasycap = file->private_data;
338         if (!peasycap) {
339                 SAY("ERROR:  peasycap is NULL.\n");
340                 return -EFAULT;
341         }
342         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
343                 SAY("ERROR: bad peasycap: %p\n", peasycap);
344                 return -EFAULT;
345         }
346         if (0 != kill_audio_urbs(peasycap)) {
347                 SAM("ERROR: kill_audio_urbs() failed\n");
348                 return -EFAULT;
349         }
350         JOM(4, "ending successfully\n");
351         return 0;
352 }
353 /*****************************************************************************/
354 static ssize_t easyoss_read(struct file *file, char __user *puserspacebuffer,
355                             size_t kount, loff_t *poff)
356 {
357         struct timeval timeval;
358         long long int above, below, mean;
359         struct signed_div_result sdr;
360         unsigned char *p0;
361         long int kount1, more, rc, l0, lm;
362         int fragment, kd;
363         struct easycap *peasycap;
364         struct data_buffer *pdata_buffer;
365         size_t szret;
366
367 /*---------------------------------------------------------------------------*/
368 /*
369  *  DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
370  *
371  ******************************************************************************
372  *****  N.B.  IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
373  *****        THIS CONDITION SIGNIFIES END-OF-FILE.                      ******
374  ******************************************************************************
375  */
376 /*---------------------------------------------------------------------------*/
377
378         JOT(8, "%5zd=kount  %5lld=*poff\n", kount, *poff);
379
380         if (!file) {
381                 SAY("ERROR:  file is NULL\n");
382                 return -ERESTARTSYS;
383         }
384         peasycap = file->private_data;
385         if (!peasycap) {
386                 SAY("ERROR in easyoss_read(): peasycap is NULL\n");
387                 return -EFAULT;
388         }
389         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
390                 SAY("ERROR: bad peasycap: %p\n", peasycap);
391                 return -EFAULT;
392         }
393         if (!peasycap->pusb_device) {
394                 SAY("ERROR: peasycap->pusb_device is NULL\n");
395                 return -EFAULT;
396         }
397         kd = isdongle(peasycap);
398         if (0 <= kd && DONGLE_MANY > kd) {
399                 if (mutex_lock_interruptible(&(easycapdc60_dongle[kd].mutex_audio))) {
400                         SAY("ERROR: "
401                             "cannot lock dongle[%i].mutex_audio\n", kd);
402                         return -ERESTARTSYS;
403                 }
404                 JOM(4, "locked dongle[%i].mutex_audio\n", kd);
405                 /*
406                  *  MEANWHILE, easycap_usb_disconnect()
407                  *  MAY HAVE FREED POINTER peasycap,
408                  *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
409                  *  IF NECESSARY, BAIL OUT.
410                  */
411                 if (kd != isdongle(peasycap))
412                         return -ERESTARTSYS;
413                 if (!file) {
414                         SAY("ERROR:  file is NULL\n");
415                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
416                         return -ERESTARTSYS;
417                 }
418                 peasycap = file->private_data;
419                 if (!peasycap) {
420                         SAY("ERROR:  peasycap is NULL\n");
421                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
422                         return -ERESTARTSYS;
423                 }
424                 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
425                         SAY("ERROR: bad peasycap: %p\n", peasycap);
426                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
427                         return -ERESTARTSYS;
428                 }
429                 if (!peasycap->pusb_device) {
430                         SAM("ERROR: peasycap->pusb_device is NULL\n");
431                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
432                         return -ERESTARTSYS;
433                 }
434         } else {
435                 /*
436                  *  IF easycap_usb_disconnect()
437                  *  HAS ALREADY FREED POINTER peasycap BEFORE THE
438                  *  ATTEMPT TO ACQUIRE THE SEMAPHORE,
439                  *  isdongle() WILL HAVE FAILED.  BAIL OUT.
440                  */
441                 return -ERESTARTSYS;
442         }
443 /*---------------------------------------------------------------------------*/
444         JOT(16, "%sBLOCKING kount=%zd, *poff=%lld\n",
445                 (file->f_flags & O_NONBLOCK) ? "NON" : "", kount, *poff);
446
447         if ((0 > peasycap->audio_read) ||
448             (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
449                 SAM("ERROR: peasycap->audio_read out of range\n");
450                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
451                 return -EFAULT;
452         }
453         pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
454         if (!pdata_buffer) {
455                 SAM("ERROR: pdata_buffer is NULL\n");
456                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
457                 return -EFAULT;
458         }
459         JOM(12, "before wait, %i=frag read  %i=frag fill\n",
460             (peasycap->audio_read / peasycap->audio_pages_per_fragment),
461             (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
462         fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
463         while ((fragment == (peasycap->audio_fill / peasycap->audio_pages_per_fragment)) ||
464                 (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
465                 if (file->f_flags & O_NONBLOCK) {
466                         JOM(16, "returning -EAGAIN as instructed\n");
467                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
468                         return -EAGAIN;
469                 }
470                 rc = wait_event_interruptible(peasycap->wq_audio,
471                                 (peasycap->audio_idle  || peasycap->audio_eof ||
472                                 ((fragment !=
473                                         (peasycap->audio_fill / peasycap->audio_pages_per_fragment)) &&
474                                 (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
475                 if (rc) {
476                         SAM("aborted by signal\n");
477                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
478                         return -ERESTARTSYS;
479                 }
480                 if (peasycap->audio_eof) {
481                         JOM(8, "returning 0 because  %i=audio_eof\n",
482                             peasycap->audio_eof);
483                         kill_audio_urbs(peasycap);
484                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
485                         return 0;
486                 }
487                 if (peasycap->audio_idle) {
488                         JOM(16, "returning 0 because  %i=audio_idle\n",
489                             peasycap->audio_idle);
490                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
491                         return 0;
492                 }
493                 if (!peasycap->audio_isoc_streaming) {
494                         JOM(16, "returning 0 because audio urbs not streaming\n");
495                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
496                         return 0;
497                 }
498         }
499         JOM(12, "after  wait, %i=frag read  %i=frag fill\n",
500             (peasycap->audio_read / peasycap->audio_pages_per_fragment),
501             (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
502         szret = (size_t)0;
503         fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
504         while (fragment == (peasycap->audio_read / peasycap->audio_pages_per_fragment)) {
505                 if (!pdata_buffer->pgo) {
506                         SAM("ERROR: pdata_buffer->pgo is NULL\n");
507                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
508                         return -EFAULT;
509                 }
510                 if (!pdata_buffer->pto) {
511                         SAM("ERROR: pdata_buffer->pto is NULL\n");
512                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
513                         return -EFAULT;
514                 }
515                 kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
516                 if (0 > kount1) {
517                         SAM("MISTAKE: kount1 is negative\n");
518                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
519                         return -ERESTARTSYS;
520                 }
521                 if (!kount1) {
522                         peasycap->audio_read++;
523                         if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
524                                 peasycap->audio_read = 0;
525                         JOM(12, "bumped peasycap->audio_read to %i\n",
526                             peasycap->audio_read);
527
528                         if (fragment != (peasycap->audio_read / peasycap->audio_pages_per_fragment))
529                                 break;
530
531                         if ((0 > peasycap->audio_read) ||
532                             (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
533                                 SAM("ERROR: peasycap->audio_read out of range\n");
534                                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
535                                 return -EFAULT;
536                         }
537                         pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
538                         if (!pdata_buffer) {
539                                 SAM("ERROR: pdata_buffer is NULL\n");
540                                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
541                                 return -EFAULT;
542                         }
543                         if (!pdata_buffer->pgo) {
544                                 SAM("ERROR: pdata_buffer->pgo is NULL\n");
545                                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
546                                 return -EFAULT;
547                         }
548                         if (!pdata_buffer->pto) {
549                                 SAM("ERROR: pdata_buffer->pto is NULL\n");
550                                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
551                                 return -EFAULT;
552                         }
553                         kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
554                 }
555                 JOM(12, "ready  to send %zd bytes\n", kount1);
556                 JOM(12, "still  to send %li bytes\n", (long int) kount);
557                 more = kount1;
558                 if (more > kount)
559                         more = kount;
560                 JOM(12, "agreed to send %li bytes from page %i\n",
561                     more, peasycap->audio_read);
562                 if (!more)
563                         break;
564
565                 /*
566                  *  ACCUMULATE DYNAMIC-RANGE INFORMATION
567                  */
568                 p0 = (unsigned char *)pdata_buffer->pgo;
569                 l0 = 0;
570                 lm = more/2;
571                 while (l0 < lm) {
572                         SUMMER(p0, &peasycap->audio_sample,
573                                 &peasycap->audio_niveau,
574                                 &peasycap->audio_square);
575                         l0++;
576                         p0 += 2;
577                 }
578                 /*-----------------------------------------------------------*/
579                 rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
580                 if (rc) {
581                         SAM("ERROR: copy_to_user() returned %li\n", rc);
582                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
583                         return -EFAULT;
584                 }
585                 *poff += (loff_t)more;
586                 szret += (size_t)more;
587                 pdata_buffer->pto += more;
588                 puserspacebuffer += more;
589                 kount -= (size_t)more;
590         }
591         JOM(12, "after  read, %i=frag read  %i=frag fill\n",
592             (peasycap->audio_read / peasycap->audio_pages_per_fragment),
593             (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
594         if (kount < 0) {
595                 SAM("MISTAKE:  %li=kount  %li=szret\n",
596                     (long int)kount, (long int)szret);
597         }
598 /*---------------------------------------------------------------------------*/
599 /*
600  *  CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
601  */
602 /*---------------------------------------------------------------------------*/
603         if (peasycap->audio_sample) {
604                 below = peasycap->audio_sample;
605                 above = peasycap->audio_square;
606                 sdr = signed_div(above, below);
607                 above = sdr.quotient;
608                 mean = peasycap->audio_niveau;
609                 sdr = signed_div(mean, peasycap->audio_sample);
610
611                 JOM(8, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n",
612                     sdr.quotient, above, peasycap->audio_sample);
613
614                 sdr = signed_div(above, 32768);
615                 JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
616         }
617 /*---------------------------------------------------------------------------*/
618 /*
619  *  UPDATE THE AUDIO CLOCK
620  */
621 /*---------------------------------------------------------------------------*/
622         do_gettimeofday(&timeval);
623         if (!peasycap->timeval1.tv_sec) {
624                 peasycap->audio_bytes = 0;
625                 peasycap->timeval3 = timeval;
626                 peasycap->timeval1 = peasycap->timeval3;
627                 sdr.quotient = 192000;
628         } else {
629                 peasycap->audio_bytes += (long long int) szret;
630                 below = ((long long int)(1000000)) *
631                         ((long long int)(timeval.tv_sec  - peasycap->timeval3.tv_sec)) +
632                         (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec);
633                 above = 1000000 * ((long long int) peasycap->audio_bytes);
634
635                 if (below)
636                         sdr = signed_div(above, below);
637                 else
638                         sdr.quotient = 192000;
639         }
640         JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
641         peasycap->dnbydt = sdr.quotient;
642
643         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
644         JOM(4, "unlocked easycapdc60_dongle[%i].mutex_audio\n", kd);
645         JOM(8, "returning %li\n", (long int)szret);
646         return szret;
647
648 }
649 /*---------------------------------------------------------------------------*/
650 static long easyoss_unlocked_ioctl(struct file *file,
651                                    unsigned int cmd, unsigned long arg)
652 {
653         struct easycap *peasycap;
654         struct usb_device *p;
655         int kd;
656
657         if (!file) {
658                 SAY("ERROR:  file is NULL\n");
659                 return -ERESTARTSYS;
660         }
661         peasycap = file->private_data;
662         if (!peasycap) {
663                 SAY("ERROR:  peasycap is NULL.\n");
664                 return -EFAULT;
665         }
666         if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
667                 SAY("ERROR: bad peasycap\n");
668                 return -EFAULT;
669         }
670         p = peasycap->pusb_device;
671         if (!p) {
672                 SAM("ERROR: peasycap->pusb_device is NULL\n");
673                 return -EFAULT;
674         }
675         kd = isdongle(peasycap);
676         if (0 <= kd && DONGLE_MANY > kd) {
677                 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
678                         SAY("ERROR: cannot lock "
679                             "easycapdc60_dongle[%i].mutex_audio\n", kd);
680                         return -ERESTARTSYS;
681                 }
682                 JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
683                 /*
684                  *  MEANWHILE, easycap_usb_disconnect()
685                  *  MAY HAVE FREED POINTER peasycap,
686                  *  IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
687                  *  IF NECESSARY, BAIL OUT.
688                 */
689                 if (kd != isdongle(peasycap))
690                         return -ERESTARTSYS;
691                 if (!file) {
692                         SAY("ERROR:  file is NULL\n");
693                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
694                         return -ERESTARTSYS;
695                 }
696                 peasycap = file->private_data;
697                 if (!peasycap) {
698                         SAY("ERROR:  peasycap is NULL\n");
699                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
700                         return -ERESTARTSYS;
701                 }
702                 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
703                         SAY("ERROR: bad peasycap\n");
704                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
705                         return -EFAULT;
706                 }
707                 p = peasycap->pusb_device;
708                 if (!peasycap->pusb_device) {
709                         SAM("ERROR: peasycap->pusb_device is NULL\n");
710                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
711                         return -ERESTARTSYS;
712                 }
713         } else {
714                 /*
715                  *  IF easycap_usb_disconnect()
716                  *  HAS ALREADY FREED POINTER peasycap BEFORE THE
717                  *  ATTEMPT TO ACQUIRE THE SEMAPHORE,
718                  *  isdongle() WILL HAVE FAILED.  BAIL OUT.
719                  */
720                 return -ERESTARTSYS;
721         }
722 /*---------------------------------------------------------------------------*/
723         switch (cmd) {
724         case SNDCTL_DSP_GETCAPS: {
725                 int caps;
726                 JOM(8, "SNDCTL_DSP_GETCAPS\n");
727
728 #ifdef UPSAMPLE
729                 if (peasycap->microphone)
730                         caps = 0x04400000;
731                 else
732                         caps = 0x04400000;
733 #else
734                 if (peasycap->microphone)
735                         caps = 0x02400000;
736                 else
737                         caps = 0x04400000;
738 #endif /*UPSAMPLE*/
739
740                 if (copy_to_user((void __user *)arg, &caps, sizeof(int))) {
741                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
742                         return -EFAULT;
743                 }
744                 break;
745         }
746         case SNDCTL_DSP_GETFMTS: {
747                 int incoming;
748                 JOM(8, "SNDCTL_DSP_GETFMTS\n");
749
750 #ifdef UPSAMPLE
751                 if (peasycap->microphone)
752                         incoming = AFMT_S16_LE;
753                 else
754                         incoming = AFMT_S16_LE;
755 #else
756                 if (peasycap->microphone)
757                         incoming = AFMT_S16_LE;
758                 else
759                         incoming = AFMT_S16_LE;
760 #endif /*UPSAMPLE*/
761
762                 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
763                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
764                         return -EFAULT;
765                 }
766                 break;
767         }
768         case SNDCTL_DSP_SETFMT: {
769                 int incoming, outgoing;
770                 JOM(8, "SNDCTL_DSP_SETFMT\n");
771                 if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
772                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
773                         return -EFAULT;
774                 }
775                 JOM(8, "........... %i=incoming\n", incoming);
776
777 #ifdef UPSAMPLE
778                 if (peasycap->microphone)
779                         outgoing = AFMT_S16_LE;
780                 else
781                         outgoing = AFMT_S16_LE;
782 #else
783                 if (peasycap->microphone)
784                         outgoing = AFMT_S16_LE;
785                 else
786                         outgoing = AFMT_S16_LE;
787 #endif /*UPSAMPLE*/
788
789                 if (incoming != outgoing) {
790                         JOM(8, "........... %i=outgoing\n", outgoing);
791                         JOM(8, "        cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
792                         JOM(8, "        cf. %i=AFMT_U8\n", AFMT_U8);
793                         if (copy_to_user((void __user *)arg, &outgoing, sizeof(int))) {
794                                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
795                                 return -EFAULT;
796                         }
797                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
798                         return -EINVAL ;
799                 }
800                 break;
801         }
802         case SNDCTL_DSP_STEREO: {
803                 int incoming;
804                 JOM(8, "SNDCTL_DSP_STEREO\n");
805                 if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
806                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
807                         return -EFAULT;
808                 }
809                 JOM(8, "........... %i=incoming\n", incoming);
810
811 #ifdef UPSAMPLE
812                 if (peasycap->microphone)
813                         incoming = 1;
814                 else
815                         incoming = 1;
816 #else
817                 if (peasycap->microphone)
818                         incoming = 0;
819                 else
820                         incoming = 1;
821 #endif /*UPSAMPLE*/
822
823                 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
824                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
825                         return -EFAULT;
826                 }
827                 break;
828         }
829         case SNDCTL_DSP_SPEED: {
830                 int incoming;
831                 JOM(8, "SNDCTL_DSP_SPEED\n");
832                 if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
833                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
834                         return -EFAULT;
835                 }
836                 JOM(8, "........... %i=incoming\n", incoming);
837
838 #ifdef UPSAMPLE
839                 if (peasycap->microphone)
840                         incoming = 32000;
841                 else
842                         incoming = 48000;
843 #else
844                 if (peasycap->microphone)
845                         incoming = 8000;
846                 else
847                         incoming = 48000;
848 #endif /*UPSAMPLE*/
849
850                 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
851                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
852                         return -EFAULT;
853                 }
854                 break;
855         }
856         case SNDCTL_DSP_GETTRIGGER: {
857                 int incoming;
858                 JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
859                 if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
860                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
861                         return -EFAULT;
862                 }
863                 JOM(8, "........... %i=incoming\n", incoming);
864
865                 incoming = PCM_ENABLE_INPUT;
866                 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
867                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
868                         return -EFAULT;
869                 }
870                 break;
871         }
872         case SNDCTL_DSP_SETTRIGGER: {
873                 int incoming;
874                 JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
875                 if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
876                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
877                         return -EFAULT;
878                 }
879                 JOM(8, "........... %i=incoming\n", incoming);
880                 JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT "
881                     "0x%x=PCM_ENABLE_OUTPUT\n",
882                     PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
883                 ;
884                 ;
885                 ;
886                 ;
887                 break;
888         }
889         case SNDCTL_DSP_GETBLKSIZE: {
890                 int incoming;
891                 JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
892                 if (copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
893                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
894                         return -EFAULT;
895                 }
896                 JOM(8, "........... %i=incoming\n", incoming);
897                 incoming = peasycap->audio_bytes_per_fragment;
898                 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
899                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
900                         return -EFAULT;
901                 }
902                 break;
903         }
904         case SNDCTL_DSP_GETISPACE: {
905                 struct audio_buf_info audio_buf_info;
906
907                 JOM(8, "SNDCTL_DSP_GETISPACE\n");
908
909                 audio_buf_info.bytes      = peasycap->audio_bytes_per_fragment;
910                 audio_buf_info.fragments  = 1;
911                 audio_buf_info.fragsize   = 0;
912                 audio_buf_info.fragstotal = 0;
913
914                 if (copy_to_user((void __user *)arg, &audio_buf_info, sizeof(int))) {
915                         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
916                         return -EFAULT;
917                 }
918                 break;
919         }
920         case 0x00005401:
921         case 0x00005402:
922         case 0x00005403:
923         case 0x00005404:
924         case 0x00005405:
925         case 0x00005406: {
926                 JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
927                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
928                 return -ENOIOCTLCMD;
929         }
930         default: {
931                 JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
932                 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
933                 return -ENOIOCTLCMD;
934         }
935         }
936         mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
937         return 0;
938 }
939 /*****************************************************************************/
940
941 static const struct file_operations easyoss_fops = {
942         .owner          = THIS_MODULE,
943         .open           = easyoss_open,
944         .release        = easyoss_release,
945         .unlocked_ioctl = easyoss_unlocked_ioctl,
946         .read           = easyoss_read,
947         .llseek         = no_llseek,
948 };
949 struct usb_class_driver easyoss_class = {
950         .name = "usb/easyoss%d",
951         .fops = &easyoss_fops,
952         .minor_base = USB_SKEL_MINOR_BASE,
953 };
954 /*****************************************************************************/