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;
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 + purb->iso_frame_desc[i].offset);
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
144 SAM("MISTAKE: more is negative\n");
147 if (peasycap->audio_buffer_page_many <= peasycap->audio_fill) {
148 SAM("ERROR: bad peasycap->audio_fill\n");
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");
157 if (PAGE_SIZE == (paudio_buffer->pto - paudio_buffer->pgo)) {
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;
164 JOM(8, "bumped peasycap->"
165 "audio_fill to %i\n",
166 peasycap->audio_fill);
168 paudio_buffer = &peasycap->audio_buffer[peasycap->audio_fill];
169 paudio_buffer->pto = paudio_buffer->pgo;
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));
179 much = PAGE_SIZE - (int)(paudio_buffer->pto - paudio_buffer->pgo);
181 if (!peasycap->microphone) {
185 memcpy(paudio_buffer->pto, p1, much);
191 JOM(8, "MISTAKE? much"
192 " is not divisible by 16\n");
193 if (much > (16 * more))
195 p2 = (u8 *)paudio_buffer->pto;
197 for (j = 0; j < (much/16); j++) {
198 newaudio = ((int) *p1) - 128;
199 newaudio = 128 * newaudio;
201 delta = (newaudio - oldaudio) / 4;
202 tmp = oldaudio + delta;
204 for (k = 0; k < 4; k++) {
205 *p2 = (0x00FF & tmp);
206 *(p2 + 1) = (0xFF00 & tmp) >> 8;
208 *p2 = (0x00FF & tmp);
209 *(p2 + 1) = (0xFF00 & tmp) >> 8;
219 if (much > (2 * more))
221 p2 = (u8 *)paudio_buffer->pto;
223 for (j = 0; j < (much / 2); j++) {
224 tmp = ((int) *p1) - 128;
226 *p2 = (0x00FF & tmp);
227 *(p2 + 1) = (0xFF00 & tmp) >> 8;
234 (paudio_buffer->pto) += much;
238 JOM(12, "discarding audio samples because "
239 "%i=purb->iso_frame_desc[i].status\n",
240 purb->iso_frame_desc[i].status);
244 peasycap->oldaudio = oldaudio;
248 /*---------------------------------------------------------------------------*/
252 /*---------------------------------------------------------------------------*/
254 if (peasycap->audio_isoc_streaming) {
255 rc = usb_submit_urb(purb, GFP_ATOMIC);
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,
267 /*****************************************************************************/
268 /*---------------------------------------------------------------------------*/
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.
274 /*---------------------------------------------------------------------------*/
275 static int easyoss_open(struct inode *inode, struct file *file)
277 struct usb_interface *pusb_interface;
278 struct easycap *peasycap;
280 struct v4l2_device *pv4l2_device;
284 subminor = iminor(inode);
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");
292 peasycap = usb_get_intfdata(pusb_interface);
294 SAY("ERROR: peasycap is NULL\n");
295 SAY("ending unsuccessfully\n");
298 /*---------------------------------------------------------------------------*/
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.
305 /*---------------------------------------------------------------------------*/
306 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
307 pv4l2_device = usb_get_intfdata(pusb_interface);
309 SAY("ERROR: pv4l2_device is NULL\n");
312 peasycap = container_of(pv4l2_device,
313 struct easycap, v4l2_device);
315 /*---------------------------------------------------------------------------*/
316 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
317 SAY("ERROR: bad peasycap: %p\n", peasycap);
320 /*---------------------------------------------------------------------------*/
322 file->private_data = peasycap;
324 if (0 != easycap_sound_setup(peasycap)) {
330 /*****************************************************************************/
331 static int easyoss_release(struct inode *inode, struct file *file)
333 struct easycap *peasycap;
337 peasycap = file->private_data;
339 SAY("ERROR: peasycap is NULL.\n");
342 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
343 SAY("ERROR: bad peasycap: %p\n", peasycap);
346 if (0 != kill_audio_urbs(peasycap)) {
347 SAM("ERROR: kill_audio_urbs() failed\n");
350 JOM(4, "ending successfully\n");
353 /*****************************************************************************/
354 static ssize_t easyoss_read(struct file *file, char __user *puserspacebuffer,
355 size_t kount, loff_t *poff)
357 struct timeval timeval;
358 long long int above, below, mean;
359 struct signed_div_result sdr;
361 long int kount1, more, rc, l0, lm;
363 struct easycap *peasycap;
364 struct data_buffer *pdata_buffer;
367 /*---------------------------------------------------------------------------*/
369 * DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
371 ******************************************************************************
372 ***** N.B. IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
373 ***** THIS CONDITION SIGNIFIES END-OF-FILE. ******
374 ******************************************************************************
376 /*---------------------------------------------------------------------------*/
378 JOT(8, "%5zd=kount %5lld=*poff\n", kount, *poff);
381 SAY("ERROR: file is NULL\n");
384 peasycap = file->private_data;
386 SAY("ERROR in easyoss_read(): peasycap is NULL\n");
389 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
390 SAY("ERROR: bad peasycap: %p\n", peasycap);
393 if (!peasycap->pusb_device) {
394 SAY("ERROR: peasycap->pusb_device is NULL\n");
397 kd = isdongle(peasycap);
398 if (0 <= kd && DONGLE_MANY > kd) {
399 if (mutex_lock_interruptible(&(easycapdc60_dongle[kd].mutex_audio))) {
401 "cannot lock dongle[%i].mutex_audio\n", kd);
404 JOM(4, "locked dongle[%i].mutex_audio\n", kd);
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.
411 if (kd != isdongle(peasycap))
414 SAY("ERROR: file is NULL\n");
415 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
418 peasycap = file->private_data;
420 SAY("ERROR: peasycap is NULL\n");
421 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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);
429 if (!peasycap->pusb_device) {
430 SAM("ERROR: peasycap->pusb_device is NULL\n");
431 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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.
443 /*---------------------------------------------------------------------------*/
444 JOT(16, "%sBLOCKING kount=%zd, *poff=%lld\n",
445 (file->f_flags & O_NONBLOCK) ? "NON" : "", kount, *poff);
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);
453 pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
455 SAM("ERROR: pdata_buffer is NULL\n");
456 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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);
470 rc = wait_event_interruptible(peasycap->wq_audio,
471 (peasycap->audio_idle || peasycap->audio_eof ||
473 (peasycap->audio_fill / peasycap->audio_pages_per_fragment)) &&
474 (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
476 SAM("aborted by signal\n");
477 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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);
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);
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);
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));
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);
510 if (!pdata_buffer->pto) {
511 SAM("ERROR: pdata_buffer->pto is NULL\n");
512 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
515 kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
517 SAM("MISTAKE: kount1 is negative\n");
518 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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);
528 if (fragment != (peasycap->audio_read / peasycap->audio_pages_per_fragment))
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);
537 pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
539 SAM("ERROR: pdata_buffer is NULL\n");
540 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
543 if (!pdata_buffer->pgo) {
544 SAM("ERROR: pdata_buffer->pgo is NULL\n");
545 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
548 if (!pdata_buffer->pto) {
549 SAM("ERROR: pdata_buffer->pto is NULL\n");
550 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
553 kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
555 JOM(12, "ready to send %zd bytes\n", kount1);
556 JOM(12, "still to send %li bytes\n", (long int) kount);
560 JOM(12, "agreed to send %li bytes from page %i\n",
561 more, peasycap->audio_read);
566 * ACCUMULATE DYNAMIC-RANGE INFORMATION
568 p0 = (unsigned char *)pdata_buffer->pgo;
572 SUMMER(p0, &peasycap->audio_sample,
573 &peasycap->audio_niveau,
574 &peasycap->audio_square);
578 /*-----------------------------------------------------------*/
579 rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
581 SAM("ERROR: copy_to_user() returned %li\n", rc);
582 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
585 *poff += (loff_t)more;
586 szret += (size_t)more;
587 pdata_buffer->pto += more;
588 puserspacebuffer += more;
589 kount -= (size_t)more;
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));
595 SAM("MISTAKE: %li=kount %li=szret\n",
596 (long int)kount, (long int)szret);
598 /*---------------------------------------------------------------------------*/
600 * CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
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);
611 JOM(8, "%8lli=mean %8lli=meansquare after %lli samples, =>\n",
612 sdr.quotient, above, peasycap->audio_sample);
614 sdr = signed_div(above, 32768);
615 JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
617 /*---------------------------------------------------------------------------*/
619 * UPDATE THE AUDIO CLOCK
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;
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);
636 sdr = signed_div(above, below);
638 sdr.quotient = 192000;
640 JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
641 peasycap->dnbydt = sdr.quotient;
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);
649 /*---------------------------------------------------------------------------*/
650 static long easyoss_unlocked_ioctl(struct file *file,
651 unsigned int cmd, unsigned long arg)
653 struct easycap *peasycap;
654 struct usb_device *p;
658 SAY("ERROR: file is NULL\n");
661 peasycap = file->private_data;
663 SAY("ERROR: peasycap is NULL.\n");
666 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
667 SAY("ERROR: bad peasycap\n");
670 p = peasycap->pusb_device;
672 SAM("ERROR: peasycap->pusb_device is NULL\n");
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);
682 JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
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.
689 if (kd != isdongle(peasycap))
692 SAY("ERROR: file is NULL\n");
693 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
696 peasycap = file->private_data;
698 SAY("ERROR: peasycap is NULL\n");
699 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
702 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
703 SAY("ERROR: bad peasycap\n");
704 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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);
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.
722 /*---------------------------------------------------------------------------*/
724 case SNDCTL_DSP_GETCAPS: {
726 JOM(8, "SNDCTL_DSP_GETCAPS\n");
729 if (peasycap->microphone)
734 if (peasycap->microphone)
740 if (copy_to_user((void __user *)arg, &caps, sizeof(int))) {
741 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
746 case SNDCTL_DSP_GETFMTS: {
748 JOM(8, "SNDCTL_DSP_GETFMTS\n");
751 if (peasycap->microphone)
752 incoming = AFMT_S16_LE;
754 incoming = AFMT_S16_LE;
756 if (peasycap->microphone)
757 incoming = AFMT_S16_LE;
759 incoming = AFMT_S16_LE;
762 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
763 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
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);
775 JOM(8, "........... %i=incoming\n", incoming);
778 if (peasycap->microphone)
779 outgoing = AFMT_S16_LE;
781 outgoing = AFMT_S16_LE;
783 if (peasycap->microphone)
784 outgoing = AFMT_S16_LE;
786 outgoing = AFMT_S16_LE;
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);
797 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
802 case SNDCTL_DSP_STEREO: {
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);
809 JOM(8, "........... %i=incoming\n", incoming);
812 if (peasycap->microphone)
817 if (peasycap->microphone)
823 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
824 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
829 case SNDCTL_DSP_SPEED: {
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);
836 JOM(8, "........... %i=incoming\n", incoming);
839 if (peasycap->microphone)
844 if (peasycap->microphone)
850 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
851 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
856 case SNDCTL_DSP_GETTRIGGER: {
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);
863 JOM(8, "........... %i=incoming\n", incoming);
865 incoming = PCM_ENABLE_INPUT;
866 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
867 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
872 case SNDCTL_DSP_SETTRIGGER: {
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);
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);
889 case SNDCTL_DSP_GETBLKSIZE: {
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);
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);
904 case SNDCTL_DSP_GETISPACE: {
905 struct audio_buf_info audio_buf_info;
907 JOM(8, "SNDCTL_DSP_GETISPACE\n");
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;
914 if (copy_to_user((void __user *)arg, &audio_buf_info, sizeof(int))) {
915 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
926 JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
927 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
931 JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
932 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
936 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
939 /*****************************************************************************/
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,
949 struct usb_class_driver easyoss_class = {
950 .name = "usb/easyoss%d",
951 .fops = &easyoss_fops,
952 .minor_base = USB_SKEL_MINOR_BASE,
954 /*****************************************************************************/