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 /*****************************************************************************/