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