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