1 /******************************************************************************
5 * Audio driver for EasyCAP USB2.0 Video Capture Device DC60 *
8 ******************************************************************************/
11 * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org>
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.
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.
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
29 /*****************************************************************************/
33 /*****************************************************************************/
34 /**************************** **************************/
35 /**************************** Open Sound System **************************/
36 /**************************** **************************/
37 /*****************************************************************************/
38 /*--------------------------------------------------------------------------*/
40 * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
42 /*--------------------------------------------------------------------------*/
43 /*****************************************************************************/
44 /*---------------------------------------------------------------------------*/
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.
50 /*---------------------------------------------------------------------------*/
52 easyoss_complete(struct urb *purb)
54 struct easycap *peasycap;
55 struct data_buffer *paudio_buffer;
58 int i, j, more, much, leap, rc;
61 s16 oldaudio, newaudio, delta;
67 SAY("ERROR: purb is NULL\n");
70 peasycap = purb->context;
71 if (NULL == peasycap) {
72 SAY("ERROR: peasycap is NULL\n");
75 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
76 SAY("ERROR: bad peasycap\n");
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);
86 if (-ENODEV != rc && -ENOENT != rc) {
87 SAM("ERROR: while %i=audio_idle, "
88 "usb_submit_urb() failed with rc: -%s: %d\n",
96 /*---------------------------------------------------------------------------*/
98 if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
99 JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
102 SAM("ERROR: non-zero urb status: -%s: %d\n",
103 strerror(purb->status), purb->status);
106 /*---------------------------------------------------------------------------*/
108 * PROCEED HERE WHEN NO ERROR
110 /*---------------------------------------------------------------------------*/
112 oldaudio = peasycap->oldaudio;
115 for (i = 0; i < purb->number_of_packets; i++) {
116 if (!purb->iso_frame_desc[i].status) {
118 SAM("-%s\n", strerror(purb->iso_frame_desc[i].status));
120 more = purb->iso_frame_desc[i].actual_length;
123 peasycap->audio_mt++;
125 if (peasycap->audio_mt) {
126 JOM(12, "%4i empty audio urb frames\n",
128 peasycap->audio_mt = 0;
131 p1 = (u8 *)(purb->transfer_buffer +
132 purb->iso_frame_desc[i].offset);
137 /*---------------------------------------------------------------------------*/
139 * COPY more BYTES FROM ISOC BUFFER TO AUDIO BUFFER,
140 * CONVERTING 8-BIT MONO TO 16-BIT SIGNED LITTLE-ENDIAN SAMPLES IF NECESSARY
142 /*---------------------------------------------------------------------------*/
145 SAM("MISTAKE: more is negative\n");
148 if (peasycap->audio_buffer_page_many <=
149 peasycap->audio_fill) {
151 "peasycap->audio_fill\n");
155 paudio_buffer = &peasycap->audio_buffer
156 [peasycap->audio_fill];
157 if (PAGE_SIZE < (paudio_buffer->pto -
158 paudio_buffer->pgo)) {
159 SAM("ERROR: bad paudio_buffer->pto\n");
162 if (PAGE_SIZE == (paudio_buffer->pto -
163 paudio_buffer->pgo)) {
167 (peasycap->audio_fill)++;
169 audio_buffer_page_many <=
170 peasycap->audio_fill)
171 peasycap->audio_fill = 0;
173 JOM(8, "bumped peasycap->"
174 "audio_fill to %i\n",
175 peasycap->audio_fill);
177 paudio_buffer = &peasycap->
179 [peasycap->audio_fill];
183 if (!(peasycap->audio_fill %
185 audio_pages_per_fragment)) {
186 JOM(12, "wakeup call on wq_"
187 "audio, %i=frag reading %i"
189 (peasycap->audio_read /
191 audio_pages_per_fragment),
192 (peasycap->audio_fill /
194 audio_pages_per_fragment));
195 wake_up_interruptible
196 (&(peasycap->wq_audio));
200 much = PAGE_SIZE - (int)(paudio_buffer->pto -
203 if (false == peasycap->microphone) {
207 memcpy(paudio_buffer->pto, p1, much);
213 JOM(8, "MISTAKE? much"
214 " is not divisible by 16\n");
219 p2 = (u8 *)paudio_buffer->pto;
221 for (j = 0; j < (much/16); j++) {
222 newaudio = ((int) *p1) - 128;
226 delta = (newaudio - oldaudio)
228 tmp = oldaudio + delta;
230 for (k = 0; k < 4; k++) {
231 *p2 = (0x00FF & tmp);
232 *(p2 + 1) = (0xFF00 &
235 *p2 = (0x00FF & tmp);
236 *(p2 + 1) = (0xFF00 &
247 if (much > (2 * more))
249 p2 = (u8 *)paudio_buffer->pto;
251 for (j = 0; j < (much / 2); j++) {
252 tmp = ((int) *p1) - 128;
255 *p2 = (0x00FF & tmp);
256 *(p2 + 1) = (0xFF00 & tmp) >>
263 (paudio_buffer->pto) += much;
267 JOM(12, "discarding audio samples because "
268 "%i=purb->iso_frame_desc[i].status\n",
269 purb->iso_frame_desc[i].status);
273 peasycap->oldaudio = oldaudio;
277 /*---------------------------------------------------------------------------*/
281 /*---------------------------------------------------------------------------*/
283 if (peasycap->audio_isoc_streaming) {
284 rc = usb_submit_urb(purb, GFP_ATOMIC);
286 if (-ENODEV != rc && -ENOENT != rc) {
287 SAM("ERROR: while %i=audio_idle, "
288 "usb_submit_urb() failed "
289 "with rc: -%s: %d\n", peasycap->audio_idle,
296 /*****************************************************************************/
297 /*---------------------------------------------------------------------------*/
299 * THE AUDIO URBS ARE SUBMITTED AT THIS EARLY STAGE SO THAT IT IS POSSIBLE TO
300 * STREAM FROM /dev/easyoss1 WITH SIMPLE PROGRAMS SUCH AS cat WHICH DO NOT
301 * HAVE AN IOCTL INTERFACE.
303 /*---------------------------------------------------------------------------*/
304 static int easyoss_open(struct inode *inode, struct file *file)
306 struct usb_interface *pusb_interface;
307 struct easycap *peasycap;
309 /*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/
310 #ifdef EASYCAP_IS_VIDEODEV_CLIENT
311 struct v4l2_device *pv4l2_device;
312 #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
313 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
317 subminor = iminor(inode);
319 pusb_interface = usb_find_interface(&easycap_usb_driver, subminor);
320 if (NULL == pusb_interface) {
321 SAY("ERROR: pusb_interface is NULL\n");
322 SAY("ending unsuccessfully\n");
325 peasycap = usb_get_intfdata(pusb_interface);
326 if (NULL == peasycap) {
327 SAY("ERROR: peasycap is NULL\n");
328 SAY("ending unsuccessfully\n");
331 /*---------------------------------------------------------------------------*/
332 #ifdef EASYCAP_IS_VIDEODEV_CLIENT
333 /*---------------------------------------------------------------------------*/
335 * SOME VERSIONS OF THE videodev MODULE OVERWRITE THE DATA WHICH HAS
336 * BEEN WRITTEN BY THE CALL TO usb_set_intfdata() IN easycap_usb_probe(),
337 * REPLACING IT WITH A POINTER TO THE EMBEDDED v4l2_device STRUCTURE.
338 * TO DETECT THIS, THE STRING IN THE easycap.telltale[] BUFFER IS CHECKED.
340 /*---------------------------------------------------------------------------*/
341 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
342 pv4l2_device = usb_get_intfdata(pusb_interface);
343 if (NULL == pv4l2_device) {
344 SAY("ERROR: pv4l2_device is NULL\n");
347 peasycap = (struct easycap *)
348 container_of(pv4l2_device, struct easycap, v4l2_device);
350 #endif /*EASYCAP_IS_VIDEODEV_CLIENT*/
351 /*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/
352 /*---------------------------------------------------------------------------*/
353 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
354 SAY("ERROR: bad peasycap: %p\n", peasycap);
357 /*---------------------------------------------------------------------------*/
359 file->private_data = peasycap;
361 if (0 != easycap_sound_setup(peasycap)) {
367 /*****************************************************************************/
368 static int easyoss_release(struct inode *inode, struct file *file)
370 struct easycap *peasycap;
374 peasycap = file->private_data;
375 if (NULL == peasycap) {
376 SAY("ERROR: peasycap is NULL.\n");
379 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
380 SAY("ERROR: bad peasycap: %p\n", peasycap);
383 if (0 != kill_audio_urbs(peasycap)) {
384 SAM("ERROR: kill_audio_urbs() failed\n");
387 JOM(4, "ending successfully\n");
390 /*****************************************************************************/
391 static ssize_t easyoss_read(struct file *file, char __user *puserspacebuffer,
392 size_t kount, loff_t *poff)
394 struct timeval timeval;
395 long long int above, below, mean;
396 struct signed_div_result sdr;
398 long int kount1, more, rc, l0, lm;
400 struct easycap *peasycap;
401 struct data_buffer *pdata_buffer;
404 /*---------------------------------------------------------------------------*/
406 * DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
408 ******************************************************************************
409 ***** N.B. IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
410 ***** THIS CONDITION SIGNIFIES END-OF-FILE. ******
411 ******************************************************************************
413 /*---------------------------------------------------------------------------*/
415 JOT(8, "%5i=kount %5i=*poff\n", (int)kount, (int)(*poff));
418 SAY("ERROR: file is NULL\n");
421 peasycap = file->private_data;
422 if (NULL == peasycap) {
423 SAY("ERROR in easyoss_read(): peasycap is NULL\n");
426 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
427 SAY("ERROR: bad peasycap: %p\n", peasycap);
430 if (NULL == peasycap->pusb_device) {
431 SAY("ERROR: peasycap->pusb_device is NULL\n");
434 kd = isdongle(peasycap);
435 if (0 <= kd && DONGLE_MANY > kd) {
436 if (mutex_lock_interruptible(&(easycapdc60_dongle[kd].mutex_audio))) {
438 "cannot lock easycapdc60_dongle[%i].mutex_audio\n", kd);
441 JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
442 /*---------------------------------------------------------------------------*/
444 * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
445 * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
446 * IF NECESSARY, BAIL OUT.
448 /*---------------------------------------------------------------------------*/
449 if (kd != isdongle(peasycap))
452 SAY("ERROR: file is NULL\n");
453 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
456 peasycap = file->private_data;
457 if (NULL == peasycap) {
458 SAY("ERROR: peasycap is NULL\n");
459 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
462 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
463 SAY("ERROR: bad peasycap: %p\n", peasycap);
464 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
467 if (NULL == peasycap->pusb_device) {
468 SAM("ERROR: peasycap->pusb_device is NULL\n");
469 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
473 /*---------------------------------------------------------------------------*/
475 * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
476 * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
478 /*---------------------------------------------------------------------------*/
481 /*---------------------------------------------------------------------------*/
482 if (file->f_flags & O_NONBLOCK)
483 JOT(16, "NONBLOCK kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
485 JOT(8, "BLOCKING kount=%i, *poff=%i\n", (int)kount, (int)(*poff));
487 if ((0 > peasycap->audio_read) ||
488 (peasycap->audio_buffer_page_many <= peasycap->audio_read)) {
489 SAM("ERROR: peasycap->audio_read out of range\n");
490 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
493 pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
494 if (NULL == pdata_buffer) {
495 SAM("ERROR: pdata_buffer is NULL\n");
496 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
499 JOM(12, "before 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 fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
503 while ((fragment == (peasycap->audio_fill /
504 peasycap->audio_pages_per_fragment)) ||
505 (0 == (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo)))) {
506 if (file->f_flags & O_NONBLOCK) {
507 JOM(16, "returning -EAGAIN as instructed\n");
508 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
511 rc = wait_event_interruptible(peasycap->wq_audio,
512 (peasycap->audio_idle || peasycap->audio_eof ||
513 ((fragment != (peasycap->audio_fill /
514 peasycap->audio_pages_per_fragment)) &&
515 (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
517 SAM("aborted by signal\n");
518 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
521 if (peasycap->audio_eof) {
522 JOM(8, "returning 0 because %i=audio_eof\n",
523 peasycap->audio_eof);
524 kill_audio_urbs(peasycap);
525 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
528 if (peasycap->audio_idle) {
529 JOM(16, "returning 0 because %i=audio_idle\n",
530 peasycap->audio_idle);
531 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
534 if (!peasycap->audio_isoc_streaming) {
535 JOM(16, "returning 0 because audio urbs not streaming\n");
536 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
540 JOM(12, "after wait, %i=frag read %i=frag fill\n",
541 (peasycap->audio_read / peasycap->audio_pages_per_fragment),
542 (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
544 fragment = (peasycap->audio_read / peasycap->audio_pages_per_fragment);
545 while (fragment == (peasycap->audio_read /
546 peasycap->audio_pages_per_fragment)) {
547 if (NULL == pdata_buffer->pgo) {
548 SAM("ERROR: pdata_buffer->pgo is NULL\n");
549 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
552 if (NULL == pdata_buffer->pto) {
553 SAM("ERROR: pdata_buffer->pto is NULL\n");
554 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
557 kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
559 SAM("MISTAKE: kount1 is negative\n");
560 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
564 (peasycap->audio_read)++;
565 if (peasycap->audio_buffer_page_many <= peasycap->audio_read)
566 peasycap->audio_read = 0;
567 JOM(12, "bumped peasycap->audio_read to %i\n",
568 peasycap->audio_read);
570 if (fragment != (peasycap->audio_read /
571 peasycap->audio_pages_per_fragment))
574 if ((0 > peasycap->audio_read) ||
575 (peasycap->audio_buffer_page_many <=
576 peasycap->audio_read)) {
577 SAM("ERROR: peasycap->audio_read out of range\n");
578 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
581 pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
582 if (NULL == pdata_buffer) {
583 SAM("ERROR: pdata_buffer is NULL\n");
584 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
587 if (NULL == pdata_buffer->pgo) {
588 SAM("ERROR: pdata_buffer->pgo is NULL\n");
589 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
592 if (NULL == pdata_buffer->pto) {
593 SAM("ERROR: pdata_buffer->pto is NULL\n");
594 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
597 kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
599 JOM(12, "ready to send %li bytes\n", (long int) kount1);
600 JOM(12, "still to send %li bytes\n", (long int) kount);
604 JOM(12, "agreed to send %li bytes from page %i\n",
605 more, peasycap->audio_read);
609 /*---------------------------------------------------------------------------*/
611 * ACCUMULATE DYNAMIC-RANGE INFORMATION
613 /*---------------------------------------------------------------------------*/
614 p0 = (unsigned char *)pdata_buffer->pgo; l0 = 0; lm = more/2;
616 SUMMER(p0, &peasycap->audio_sample, &peasycap->audio_niveau,
617 &peasycap->audio_square); l0++; p0 += 2;
619 /*---------------------------------------------------------------------------*/
620 rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
622 SAM("ERROR: copy_to_user() returned %li\n", rc);
623 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
626 *poff += (loff_t)more;
627 szret += (size_t)more;
628 pdata_buffer->pto += more;
629 puserspacebuffer += more;
630 kount -= (size_t)more;
632 JOM(12, "after read, %i=frag read %i=frag fill\n",
633 (peasycap->audio_read / peasycap->audio_pages_per_fragment),
634 (peasycap->audio_fill / peasycap->audio_pages_per_fragment));
636 SAM("MISTAKE: %li=kount %li=szret\n",
637 (long int)kount, (long int)szret);
639 /*---------------------------------------------------------------------------*/
641 * CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
643 /*---------------------------------------------------------------------------*/
644 if (peasycap->audio_sample) {
645 below = peasycap->audio_sample;
646 above = peasycap->audio_square;
647 sdr = signed_div(above, below);
648 above = sdr.quotient;
649 mean = peasycap->audio_niveau;
650 sdr = signed_div(mean, peasycap->audio_sample);
652 JOM(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n",
653 sdr.quotient, above, peasycap->audio_sample);
655 sdr = signed_div(above, 32768);
656 JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
658 /*---------------------------------------------------------------------------*/
660 * UPDATE THE AUDIO CLOCK
662 /*---------------------------------------------------------------------------*/
663 do_gettimeofday(&timeval);
664 if (!peasycap->timeval1.tv_sec) {
665 peasycap->audio_bytes = 0;
666 peasycap->timeval3 = timeval;
667 peasycap->timeval1 = peasycap->timeval3;
668 sdr.quotient = 192000;
670 peasycap->audio_bytes += (long long int) szret;
671 below = ((long long int)(1000000)) *
672 ((long long int)(timeval.tv_sec -
673 peasycap->timeval3.tv_sec)) +
674 (long long int)(timeval.tv_usec - peasycap->timeval3.tv_usec);
675 above = 1000000 * ((long long int) peasycap->audio_bytes);
678 sdr = signed_div(above, below);
680 sdr.quotient = 192000;
682 JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
683 peasycap->dnbydt = sdr.quotient;
685 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
686 JOM(4, "unlocked easycapdc60_dongle[%i].mutex_audio\n", kd);
687 JOM(8, "returning %li\n", (long int)szret);
691 /*---------------------------------------------------------------------------*/
692 static long easyoss_unlocked_ioctl(struct file *file,
693 unsigned int cmd, unsigned long arg)
695 struct easycap *peasycap;
696 struct usb_device *p;
700 SAY("ERROR: file is NULL\n");
703 peasycap = file->private_data;
704 if (NULL == peasycap) {
705 SAY("ERROR: peasycap is NULL.\n");
708 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
709 SAY("ERROR: bad peasycap\n");
712 p = peasycap->pusb_device;
714 SAM("ERROR: peasycap->pusb_device is NULL\n");
717 kd = isdongle(peasycap);
718 if (0 <= kd && DONGLE_MANY > kd) {
719 if (mutex_lock_interruptible(&easycapdc60_dongle[kd].mutex_audio)) {
720 SAY("ERROR: cannot lock "
721 "easycapdc60_dongle[%i].mutex_audio\n", kd);
724 JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
725 /*---------------------------------------------------------------------------*/
727 * MEANWHILE, easycap_usb_disconnect() MAY HAVE FREED POINTER peasycap,
728 * IN WHICH CASE A REPEAT CALL TO isdongle() WILL FAIL.
729 * IF NECESSARY, BAIL OUT.
731 /*---------------------------------------------------------------------------*/
732 if (kd != isdongle(peasycap))
735 SAY("ERROR: file is NULL\n");
736 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
739 peasycap = file->private_data;
740 if (NULL == peasycap) {
741 SAY("ERROR: peasycap is NULL\n");
742 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
745 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
746 SAY("ERROR: bad peasycap\n");
747 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
750 p = peasycap->pusb_device;
751 if (NULL == peasycap->pusb_device) {
752 SAM("ERROR: peasycap->pusb_device is NULL\n");
753 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
757 /*---------------------------------------------------------------------------*/
759 * IF easycap_usb_disconnect() HAS ALREADY FREED POINTER peasycap BEFORE THE
760 * ATTEMPT TO ACQUIRE THE SEMAPHORE, isdongle() WILL HAVE FAILED. BAIL OUT.
762 /*---------------------------------------------------------------------------*/
765 /*---------------------------------------------------------------------------*/
767 case SNDCTL_DSP_GETCAPS: {
769 JOM(8, "SNDCTL_DSP_GETCAPS\n");
772 if (true == peasycap->microphone)
777 if (true == peasycap->microphone)
783 if (0 != copy_to_user((void __user *)arg, &caps, sizeof(int))) {
784 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
789 case SNDCTL_DSP_GETFMTS: {
791 JOM(8, "SNDCTL_DSP_GETFMTS\n");
794 if (true == peasycap->microphone)
795 incoming = AFMT_S16_LE;
797 incoming = AFMT_S16_LE;
799 if (true == peasycap->microphone)
800 incoming = AFMT_S16_LE;
802 incoming = AFMT_S16_LE;
805 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
806 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
811 case SNDCTL_DSP_SETFMT: {
812 int incoming, outgoing;
813 JOM(8, "SNDCTL_DSP_SETFMT\n");
814 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
815 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
818 JOM(8, "........... %i=incoming\n", incoming);
821 if (true == peasycap->microphone)
822 outgoing = AFMT_S16_LE;
824 outgoing = AFMT_S16_LE;
826 if (true == peasycap->microphone)
827 outgoing = AFMT_S16_LE;
829 outgoing = AFMT_S16_LE;
832 if (incoming != outgoing) {
833 JOM(8, "........... %i=outgoing\n", outgoing);
834 JOM(8, " cf. %i=AFMT_S16_LE\n", AFMT_S16_LE);
835 JOM(8, " cf. %i=AFMT_U8\n", AFMT_U8);
836 if (0 != copy_to_user((void __user *)arg, &outgoing,
838 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
841 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
846 case SNDCTL_DSP_STEREO: {
848 JOM(8, "SNDCTL_DSP_STEREO\n");
849 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
850 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
853 JOM(8, "........... %i=incoming\n", incoming);
856 if (true == peasycap->microphone)
861 if (true == peasycap->microphone)
867 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
868 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
873 case SNDCTL_DSP_SPEED: {
875 JOM(8, "SNDCTL_DSP_SPEED\n");
876 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
877 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
880 JOM(8, "........... %i=incoming\n", incoming);
883 if (true == peasycap->microphone)
888 if (true == peasycap->microphone)
894 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
895 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
900 case SNDCTL_DSP_GETTRIGGER: {
902 JOM(8, "SNDCTL_DSP_GETTRIGGER\n");
903 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
904 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
907 JOM(8, "........... %i=incoming\n", incoming);
909 incoming = PCM_ENABLE_INPUT;
910 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
911 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
916 case SNDCTL_DSP_SETTRIGGER: {
918 JOM(8, "SNDCTL_DSP_SETTRIGGER\n");
919 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
920 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
923 JOM(8, "........... %i=incoming\n", incoming);
924 JOM(8, "........... cf 0x%x=PCM_ENABLE_INPUT "
925 "0x%x=PCM_ENABLE_OUTPUT\n",
926 PCM_ENABLE_INPUT, PCM_ENABLE_OUTPUT);
933 case SNDCTL_DSP_GETBLKSIZE: {
935 JOM(8, "SNDCTL_DSP_GETBLKSIZE\n");
936 if (0 != copy_from_user(&incoming, (void __user *)arg, sizeof(int))) {
937 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
940 JOM(8, "........... %i=incoming\n", incoming);
941 incoming = peasycap->audio_bytes_per_fragment;
942 if (0 != copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
943 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
948 case SNDCTL_DSP_GETISPACE: {
949 struct audio_buf_info audio_buf_info;
951 JOM(8, "SNDCTL_DSP_GETISPACE\n");
953 audio_buf_info.bytes = peasycap->audio_bytes_per_fragment;
954 audio_buf_info.fragments = 1;
955 audio_buf_info.fragsize = 0;
956 audio_buf_info.fragstotal = 0;
958 if (0 != copy_to_user((void __user *)arg, &audio_buf_info,
960 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
971 JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
972 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
976 JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
977 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
981 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
984 /*****************************************************************************/
986 static const struct file_operations easyoss_fops = {
987 .owner = THIS_MODULE,
988 .open = easyoss_open,
989 .release = easyoss_release,
990 .unlocked_ioctl = easyoss_unlocked_ioctl,
991 .read = easyoss_read,
994 struct usb_class_driver easyoss_class = {
995 .name = "usb/easyoss%d",
996 .fops = &easyoss_fops,
997 .minor_base = USB_SKEL_MINOR_BASE,
999 /*****************************************************************************/