~ubuntu-branches/ubuntu/precise/linux-ti-omap4/precise

« back to all changes in this revision

Viewing changes to drivers/staging/easycap/easycap_sound_oss.c

  • Committer: Bazaar Package Importer
  • Author(s): Paolo Pisati
  • Date: 2011-06-29 15:23:51 UTC
  • mfrom: (26.1.1 natty-proposed)
  • Revision ID: james.westby@ubuntu.com-20110629152351-xs96tm303d95rpbk
Tags: 3.0.0-1200.2
* Rebased against 3.0.0-6.7
* BSP from TI based on 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/******************************************************************************
 
2
*                                                                             *
 
3
*  easycap_sound.c                                                            *
 
4
*                                                                             *
 
5
*  Audio driver for EasyCAP USB2.0 Video Capture Device DC60                  *
 
6
*                                                                             *
 
7
*                                                                             *
 
8
******************************************************************************/
 
9
/*
 
10
 *
 
11
 *  Copyright (C) 2010 R.M. Thomas  <rmthomas@sciolus.org>
 
12
 *
 
13
 *
 
14
 *  This is free software; you can redistribute it and/or modify
 
15
 *  it under the terms of the GNU General Public License as published by
 
16
 *  the Free Software Foundation; either version 2 of the License, or
 
17
 *  (at your option) any later version.
 
18
 *
 
19
 *  The software is distributed in the hope that it will be useful,
 
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
22
 *  GNU General Public License for more details.
 
23
 *
 
24
 *  You should have received a copy of the GNU General Public License
 
25
 *  along with this software; if not, write to the Free Software
 
26
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
27
 *
 
28
*/
 
29
/*****************************************************************************/
 
30
 
 
31
#include "easycap.h"
 
32
 
 
33
/*****************************************************************************/
 
34
/****************************                       **************************/
 
35
/****************************   Open Sound System   **************************/
 
36
/****************************                       **************************/
 
37
/*****************************************************************************/
 
38
/*--------------------------------------------------------------------------*/
 
39
/*
 
40
 *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
 
41
 */
 
42
/*--------------------------------------------------------------------------*/
 
43
/*****************************************************************************/
 
44
/*---------------------------------------------------------------------------*/
 
45
/*
 
46
 *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE AUDIO BUFFERS
 
47
 *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
 
48
 *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
 
49
 */
 
50
/*---------------------------------------------------------------------------*/
 
51
void
 
52
easyoss_complete(struct urb *purb)
 
53
{
 
54
        struct easycap *peasycap;
 
55
        struct data_buffer *paudio_buffer;
 
56
        u8 *p1, *p2;
 
57
        s16 tmp;
 
58
        int i, j, more, much, leap, rc;
 
59
#ifdef UPSAMPLE
 
60
        int k;
 
61
        s16 oldaudio, newaudio, delta;
 
62
#endif /*UPSAMPLE*/
 
63
 
 
64
        JOT(16, "\n");
 
65
 
 
66
        if (!purb) {
 
67
                SAY("ERROR: purb is NULL\n");
 
68
                return;
 
69
        }
 
70
        peasycap = purb->context;
 
71
        if (!peasycap) {
 
72
                SAY("ERROR: peasycap is NULL\n");
 
73
                return;
 
74
        }
 
75
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
76
                SAY("ERROR: bad peasycap\n");
 
77
                return;
 
78
        }
 
79
        much = 0;
 
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);
 
85
                        if (rc) {
 
86
                                if (-ENODEV != rc && -ENOENT != rc) {
 
87
                                        SAM("ERROR: while %i=audio_idle, "
 
88
                                            "usb_submit_urb() failed with rc: -%s: %d\n",
 
89
                                            peasycap->audio_idle,
 
90
                                            strerror(rc), rc);
 
91
                                }
 
92
                        }
 
93
                }
 
94
                return;
 
95
        }
 
96
/*---------------------------------------------------------------------------*/
 
97
        if (purb->status) {
 
98
                if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
 
99
                        JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
 
100
                        return;
 
101
                }
 
102
                SAM("ERROR: non-zero urb status: -%s: %d\n",
 
103
                    strerror(purb->status), purb->status);
 
104
                goto resubmit;
 
105
        }
 
106
/*---------------------------------------------------------------------------*/
 
107
/*
 
108
 *  PROCEED HERE WHEN NO ERROR
 
109
 */
 
110
/*---------------------------------------------------------------------------*/
 
111
#ifdef UPSAMPLE
 
112
        oldaudio = peasycap->oldaudio;
 
113
#endif /*UPSAMPLE*/
 
114
 
 
115
        for (i = 0;  i < purb->number_of_packets; i++) {
 
116
                if (!purb->iso_frame_desc[i].status) {
 
117
 
 
118
                        SAM("-%s\n", strerror(purb->iso_frame_desc[i].status));
 
119
 
 
120
                        more = purb->iso_frame_desc[i].actual_length;
 
121
 
 
122
                        if (!more)
 
123
                                peasycap->audio_mt++;
 
124
                        else {
 
125
                                if (peasycap->audio_mt) {
 
126
                                        JOM(12, "%4i empty audio urb frames\n",
 
127
                                            peasycap->audio_mt);
 
128
                                        peasycap->audio_mt = 0;
 
129
                                }
 
130
 
 
131
                                p1 = (u8 *)(purb->transfer_buffer + purb->iso_frame_desc[i].offset);
 
132
 
 
133
                                leap = 0;
 
134
                                p1 += leap;
 
135
                                more -= leap;
 
136
                                /*
 
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
 
141
                                 */
 
142
                                while (more) {
 
143
                                        if (0 > more) {
 
144
                                                SAM("MISTAKE: more is negative\n");
 
145
                                                return;
 
146
                                        }
 
147
                                        if (peasycap->audio_buffer_page_many <= peasycap->audio_fill) {
 
148
                                                SAM("ERROR: bad peasycap->audio_fill\n");
 
149
                                                return;
 
150
                                        }
 
151
 
 
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");
 
155
                                                return;
 
156
                                        }
 
157
                                        if (PAGE_SIZE == (paudio_buffer->pto - paudio_buffer->pgo)) {
 
158
 
 
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;
 
163
 
 
164
                                                JOM(8, "bumped peasycap->"
 
165
                                                    "audio_fill to %i\n",
 
166
                                                    peasycap->audio_fill);
 
167
 
 
168
                                                paudio_buffer = &peasycap->audio_buffer[peasycap->audio_fill];
 
169
                                                paudio_buffer->pto = paudio_buffer->pgo;
 
170
 
 
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));
 
176
                                                }
 
177
                                        }
 
178
 
 
179
                                        much = PAGE_SIZE - (int)(paudio_buffer->pto - paudio_buffer->pgo);
 
180
 
 
181
                                        if (!peasycap->microphone) {
 
182
                                                if (much > more)
 
183
                                                        much = more;
 
184
 
 
185
                                                memcpy(paudio_buffer->pto, p1, much);
 
186
                                                p1 += much;
 
187
                                                more -= much;
 
188
                                        } else {
 
189
#ifdef UPSAMPLE
 
190
                                                if (much % 16)
 
191
                                                        JOM(8, "MISTAKE? much"
 
192
                                                            " is not divisible by 16\n");
 
193
                                                if (much > (16 * more))
 
194
                                                        much = 16 * more;
 
195
                                                p2 = (u8 *)paudio_buffer->pto;
 
196
 
 
197
                                                for (j = 0;  j < (much/16);  j++) {
 
198
                                                        newaudio =  ((int) *p1) - 128;
 
199
                                                        newaudio = 128 * newaudio;
 
200
 
 
201
                                                        delta = (newaudio - oldaudio) / 4;
 
202
                                                        tmp = oldaudio + delta;
 
203
 
 
204
                                                        for (k = 0;  k < 4;  k++) {
 
205
                                                                *p2 = (0x00FF & tmp);
 
206
                                                                *(p2 + 1) = (0xFF00 & tmp) >> 8;
 
207
                                                                p2 += 2;
 
208
                                                                *p2 = (0x00FF & tmp);
 
209
                                                                *(p2 + 1) = (0xFF00 & tmp) >> 8;
 
210
                                                                p2 += 2;
 
211
 
 
212
                                                                tmp += delta;
 
213
                                                        }
 
214
                                                        p1++;
 
215
                                                        more--;
 
216
                                                        oldaudio = tmp;
 
217
                                                }
 
218
#else /*!UPSAMPLE*/
 
219
                                                if (much > (2 * more))
 
220
                                                        much = 2 * more;
 
221
                                                p2 = (u8 *)paudio_buffer->pto;
 
222
 
 
223
                                                for (j = 0;  j < (much / 2);  j++) {
 
224
                                                        tmp =  ((int) *p1) - 128;
 
225
                                                        tmp = 128 * tmp;
 
226
                                                        *p2 = (0x00FF & tmp);
 
227
                                                        *(p2 + 1) = (0xFF00 & tmp) >> 8;
 
228
                                                        p1++;
 
229
                                                        p2 += 2;
 
230
                                                        more--;
 
231
                                                }
 
232
#endif /*UPSAMPLE*/
 
233
                                        }
 
234
                                        (paudio_buffer->pto) += much;
 
235
                                }
 
236
                        }
 
237
                } else {
 
238
                        JOM(12, "discarding audio samples because "
 
239
                            "%i=purb->iso_frame_desc[i].status\n",
 
240
                            purb->iso_frame_desc[i].status);
 
241
                }
 
242
 
 
243
#ifdef UPSAMPLE
 
244
                peasycap->oldaudio = oldaudio;
 
245
#endif /*UPSAMPLE*/
 
246
 
 
247
        }
 
248
/*---------------------------------------------------------------------------*/
 
249
/*
 
250
 *  RESUBMIT THIS URB
 
251
 */
 
252
/*---------------------------------------------------------------------------*/
 
253
resubmit:
 
254
        if (peasycap->audio_isoc_streaming) {
 
255
                rc = usb_submit_urb(purb, GFP_ATOMIC);
 
256
                if (rc) {
 
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,
 
261
                                    strerror(rc), rc);
 
262
                        }
 
263
                }
 
264
        }
 
265
        return;
 
266
}
 
267
/*****************************************************************************/
 
268
/*---------------------------------------------------------------------------*/
 
269
/*
 
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.
 
273
 */
 
274
/*---------------------------------------------------------------------------*/
 
275
static int easyoss_open(struct inode *inode, struct file *file)
 
276
{
 
277
        struct usb_interface *pusb_interface;
 
278
        struct easycap *peasycap;
 
279
        int subminor;
 
280
        struct v4l2_device *pv4l2_device;
 
281
 
 
282
        JOT(4, "begins\n");
 
283
 
 
284
        subminor = iminor(inode);
 
285
 
 
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");
 
290
                return -1;
 
291
        }
 
292
        peasycap = usb_get_intfdata(pusb_interface);
 
293
        if (!peasycap) {
 
294
                SAY("ERROR: peasycap is NULL\n");
 
295
                SAY("ending unsuccessfully\n");
 
296
                return -1;
 
297
        }
 
298
/*---------------------------------------------------------------------------*/
 
299
/*
 
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.
 
304
*/
 
305
/*---------------------------------------------------------------------------*/
 
306
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
307
                pv4l2_device = usb_get_intfdata(pusb_interface);
 
308
                if (!pv4l2_device) {
 
309
                        SAY("ERROR: pv4l2_device is NULL\n");
 
310
                        return -EFAULT;
 
311
                }
 
312
                peasycap = container_of(pv4l2_device,
 
313
                                struct easycap, v4l2_device);
 
314
        }
 
315
/*---------------------------------------------------------------------------*/
 
316
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
317
                SAY("ERROR: bad peasycap: %p\n", peasycap);
 
318
                return -EFAULT;
 
319
        }
 
320
/*---------------------------------------------------------------------------*/
 
321
 
 
322
        file->private_data = peasycap;
 
323
 
 
324
        if (0 != easycap_sound_setup(peasycap)) {
 
325
                ;
 
326
                ;
 
327
        }
 
328
        return 0;
 
329
}
 
330
/*****************************************************************************/
 
331
static int easyoss_release(struct inode *inode, struct file *file)
 
332
{
 
333
        struct easycap *peasycap;
 
334
 
 
335
        JOT(4, "begins\n");
 
336
 
 
337
        peasycap = file->private_data;
 
338
        if (!peasycap) {
 
339
                SAY("ERROR:  peasycap is NULL.\n");
 
340
                return -EFAULT;
 
341
        }
 
342
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
343
                SAY("ERROR: bad peasycap: %p\n", peasycap);
 
344
                return -EFAULT;
 
345
        }
 
346
        if (0 != kill_audio_urbs(peasycap)) {
 
347
                SAM("ERROR: kill_audio_urbs() failed\n");
 
348
                return -EFAULT;
 
349
        }
 
350
        JOM(4, "ending successfully\n");
 
351
        return 0;
 
352
}
 
353
/*****************************************************************************/
 
354
static ssize_t easyoss_read(struct file *file, char __user *puserspacebuffer,
 
355
                            size_t kount, loff_t *poff)
 
356
{
 
357
        struct timeval timeval;
 
358
        long long int above, below, mean;
 
359
        struct signed_div_result sdr;
 
360
        unsigned char *p0;
 
361
        long int kount1, more, rc, l0, lm;
 
362
        int fragment, kd;
 
363
        struct easycap *peasycap;
 
364
        struct data_buffer *pdata_buffer;
 
365
        size_t szret;
 
366
 
 
367
/*---------------------------------------------------------------------------*/
 
368
/*
 
369
 *  DO A BLOCKING READ TO TRANSFER DATA TO USER SPACE.
 
370
 *
 
371
 ******************************************************************************
 
372
 *****  N.B.  IF THIS FUNCTION RETURNS 0, NOTHING IS SEEN IN USER SPACE. ******
 
373
 *****        THIS CONDITION SIGNIFIES END-OF-FILE.                      ******
 
374
 ******************************************************************************
 
375
 */
 
376
/*---------------------------------------------------------------------------*/
 
377
 
 
378
        JOT(8, "%5zd=kount  %5lld=*poff\n", kount, *poff);
 
379
 
 
380
        if (!file) {
 
381
                SAY("ERROR:  file is NULL\n");
 
382
                return -ERESTARTSYS;
 
383
        }
 
384
        peasycap = file->private_data;
 
385
        if (!peasycap) {
 
386
                SAY("ERROR in easyoss_read(): peasycap is NULL\n");
 
387
                return -EFAULT;
 
388
        }
 
389
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
390
                SAY("ERROR: bad peasycap: %p\n", peasycap);
 
391
                return -EFAULT;
 
392
        }
 
393
        if (!peasycap->pusb_device) {
 
394
                SAY("ERROR: peasycap->pusb_device is NULL\n");
 
395
                return -EFAULT;
 
396
        }
 
397
        kd = isdongle(peasycap);
 
398
        if (0 <= kd && DONGLE_MANY > kd) {
 
399
                if (mutex_lock_interruptible(&(easycapdc60_dongle[kd].mutex_audio))) {
 
400
                        SAY("ERROR: "
 
401
                            "cannot lock dongle[%i].mutex_audio\n", kd);
 
402
                        return -ERESTARTSYS;
 
403
                }
 
404
                JOM(4, "locked dongle[%i].mutex_audio\n", kd);
 
405
                /*
 
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.
 
410
                 */
 
411
                if (kd != isdongle(peasycap))
 
412
                        return -ERESTARTSYS;
 
413
                if (!file) {
 
414
                        SAY("ERROR:  file is NULL\n");
 
415
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
416
                        return -ERESTARTSYS;
 
417
                }
 
418
                peasycap = file->private_data;
 
419
                if (!peasycap) {
 
420
                        SAY("ERROR:  peasycap is NULL\n");
 
421
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
422
                        return -ERESTARTSYS;
 
423
                }
 
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);
 
427
                        return -ERESTARTSYS;
 
428
                }
 
429
                if (!peasycap->pusb_device) {
 
430
                        SAM("ERROR: peasycap->pusb_device is NULL\n");
 
431
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
432
                        return -ERESTARTSYS;
 
433
                }
 
434
        } else {
 
435
                /*
 
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.
 
440
                 */
 
441
                return -ERESTARTSYS;
 
442
        }
 
443
/*---------------------------------------------------------------------------*/
 
444
        JOT(16, "%sBLOCKING kount=%zd, *poff=%lld\n",
 
445
                (file->f_flags & O_NONBLOCK) ? "NON" : "", kount, *poff);
 
446
 
 
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);
 
451
                return -EFAULT;
 
452
        }
 
453
        pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
 
454
        if (!pdata_buffer) {
 
455
                SAM("ERROR: pdata_buffer is NULL\n");
 
456
                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
457
                return -EFAULT;
 
458
        }
 
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);
 
468
                        return -EAGAIN;
 
469
                }
 
470
                rc = wait_event_interruptible(peasycap->wq_audio,
 
471
                                (peasycap->audio_idle  || peasycap->audio_eof ||
 
472
                                ((fragment !=
 
473
                                        (peasycap->audio_fill / peasycap->audio_pages_per_fragment)) &&
 
474
                                (0 < (PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo))))));
 
475
                if (rc) {
 
476
                        SAM("aborted by signal\n");
 
477
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
478
                        return -ERESTARTSYS;
 
479
                }
 
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);
 
485
                        return 0;
 
486
                }
 
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);
 
491
                        return 0;
 
492
                }
 
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);
 
496
                        return 0;
 
497
                }
 
498
        }
 
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));
 
502
        szret = (size_t)0;
 
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);
 
508
                        return -EFAULT;
 
509
                }
 
510
                if (!pdata_buffer->pto) {
 
511
                        SAM("ERROR: pdata_buffer->pto is NULL\n");
 
512
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
513
                        return -EFAULT;
 
514
                }
 
515
                kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
 
516
                if (0 > kount1) {
 
517
                        SAM("MISTAKE: kount1 is negative\n");
 
518
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
519
                        return -ERESTARTSYS;
 
520
                }
 
521
                if (!kount1) {
 
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);
 
527
 
 
528
                        if (fragment != (peasycap->audio_read / peasycap->audio_pages_per_fragment))
 
529
                                break;
 
530
 
 
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);
 
535
                                return -EFAULT;
 
536
                        }
 
537
                        pdata_buffer = &peasycap->audio_buffer[peasycap->audio_read];
 
538
                        if (!pdata_buffer) {
 
539
                                SAM("ERROR: pdata_buffer is NULL\n");
 
540
                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
541
                                return -EFAULT;
 
542
                        }
 
543
                        if (!pdata_buffer->pgo) {
 
544
                                SAM("ERROR: pdata_buffer->pgo is NULL\n");
 
545
                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
546
                                return -EFAULT;
 
547
                        }
 
548
                        if (!pdata_buffer->pto) {
 
549
                                SAM("ERROR: pdata_buffer->pto is NULL\n");
 
550
                                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
551
                                return -EFAULT;
 
552
                        }
 
553
                        kount1 = PAGE_SIZE - (pdata_buffer->pto - pdata_buffer->pgo);
 
554
                }
 
555
                JOM(12, "ready  to send %zd bytes\n", kount1);
 
556
                JOM(12, "still  to send %li bytes\n", (long int) kount);
 
557
                more = kount1;
 
558
                if (more > kount)
 
559
                        more = kount;
 
560
                JOM(12, "agreed to send %li bytes from page %i\n",
 
561
                    more, peasycap->audio_read);
 
562
                if (!more)
 
563
                        break;
 
564
 
 
565
                /*
 
566
                 *  ACCUMULATE DYNAMIC-RANGE INFORMATION
 
567
                 */
 
568
                p0 = (unsigned char *)pdata_buffer->pgo;
 
569
                l0 = 0;
 
570
                lm = more/2;
 
571
                while (l0 < lm) {
 
572
                        SUMMER(p0, &peasycap->audio_sample,
 
573
                                &peasycap->audio_niveau,
 
574
                                &peasycap->audio_square);
 
575
                        l0++;
 
576
                        p0 += 2;
 
577
                }
 
578
                /*-----------------------------------------------------------*/
 
579
                rc = copy_to_user(puserspacebuffer, pdata_buffer->pto, more);
 
580
                if (rc) {
 
581
                        SAM("ERROR: copy_to_user() returned %li\n", rc);
 
582
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
583
                        return -EFAULT;
 
584
                }
 
585
                *poff += (loff_t)more;
 
586
                szret += (size_t)more;
 
587
                pdata_buffer->pto += more;
 
588
                puserspacebuffer += more;
 
589
                kount -= (size_t)more;
 
590
        }
 
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));
 
594
        if (kount < 0) {
 
595
                SAM("MISTAKE:  %li=kount  %li=szret\n",
 
596
                    (long int)kount, (long int)szret);
 
597
        }
 
598
/*---------------------------------------------------------------------------*/
 
599
/*
 
600
 *  CALCULATE DYNAMIC RANGE FOR (VAPOURWARE) AUTOMATIC VOLUME CONTROL
 
601
 */
 
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);
 
610
 
 
611
                JOM(8, "%8lli=mean  %8lli=meansquare after %lli samples, =>\n",
 
612
                    sdr.quotient, above, peasycap->audio_sample);
 
613
 
 
614
                sdr = signed_div(above, 32768);
 
615
                JOM(8, "audio dynamic range is roughly %lli\n", sdr.quotient);
 
616
        }
 
617
/*---------------------------------------------------------------------------*/
 
618
/*
 
619
 *  UPDATE THE AUDIO CLOCK
 
620
 */
 
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;
 
628
        } else {
 
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);
 
634
 
 
635
                if (below)
 
636
                        sdr = signed_div(above, below);
 
637
                else
 
638
                        sdr.quotient = 192000;
 
639
        }
 
640
        JOM(8, "audio streaming at %lli bytes/second\n", sdr.quotient);
 
641
        peasycap->dnbydt = sdr.quotient;
 
642
 
 
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);
 
646
        return szret;
 
647
 
 
648
}
 
649
/*---------------------------------------------------------------------------*/
 
650
static long easyoss_unlocked_ioctl(struct file *file,
 
651
                                   unsigned int cmd, unsigned long arg)
 
652
{
 
653
        struct easycap *peasycap;
 
654
        struct usb_device *p;
 
655
        int kd;
 
656
 
 
657
        if (!file) {
 
658
                SAY("ERROR:  file is NULL\n");
 
659
                return -ERESTARTSYS;
 
660
        }
 
661
        peasycap = file->private_data;
 
662
        if (!peasycap) {
 
663
                SAY("ERROR:  peasycap is NULL.\n");
 
664
                return -EFAULT;
 
665
        }
 
666
        if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
667
                SAY("ERROR: bad peasycap\n");
 
668
                return -EFAULT;
 
669
        }
 
670
        p = peasycap->pusb_device;
 
671
        if (!p) {
 
672
                SAM("ERROR: peasycap->pusb_device is NULL\n");
 
673
                return -EFAULT;
 
674
        }
 
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);
 
680
                        return -ERESTARTSYS;
 
681
                }
 
682
                JOM(4, "locked easycapdc60_dongle[%i].mutex_audio\n", kd);
 
683
                /*
 
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.
 
688
                */
 
689
                if (kd != isdongle(peasycap))
 
690
                        return -ERESTARTSYS;
 
691
                if (!file) {
 
692
                        SAY("ERROR:  file is NULL\n");
 
693
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
694
                        return -ERESTARTSYS;
 
695
                }
 
696
                peasycap = file->private_data;
 
697
                if (!peasycap) {
 
698
                        SAY("ERROR:  peasycap is NULL\n");
 
699
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
700
                        return -ERESTARTSYS;
 
701
                }
 
702
                if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
 
703
                        SAY("ERROR: bad peasycap\n");
 
704
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
705
                        return -EFAULT;
 
706
                }
 
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);
 
711
                        return -ERESTARTSYS;
 
712
                }
 
713
        } else {
 
714
                /*
 
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.
 
719
                 */
 
720
                return -ERESTARTSYS;
 
721
        }
 
722
/*---------------------------------------------------------------------------*/
 
723
        switch (cmd) {
 
724
        case SNDCTL_DSP_GETCAPS: {
 
725
                int caps;
 
726
                JOM(8, "SNDCTL_DSP_GETCAPS\n");
 
727
 
 
728
#ifdef UPSAMPLE
 
729
                if (peasycap->microphone)
 
730
                        caps = 0x04400000;
 
731
                else
 
732
                        caps = 0x04400000;
 
733
#else
 
734
                if (peasycap->microphone)
 
735
                        caps = 0x02400000;
 
736
                else
 
737
                        caps = 0x04400000;
 
738
#endif /*UPSAMPLE*/
 
739
 
 
740
                if (copy_to_user((void __user *)arg, &caps, sizeof(int))) {
 
741
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
742
                        return -EFAULT;
 
743
                }
 
744
                break;
 
745
        }
 
746
        case SNDCTL_DSP_GETFMTS: {
 
747
                int incoming;
 
748
                JOM(8, "SNDCTL_DSP_GETFMTS\n");
 
749
 
 
750
#ifdef UPSAMPLE
 
751
                if (peasycap->microphone)
 
752
                        incoming = AFMT_S16_LE;
 
753
                else
 
754
                        incoming = AFMT_S16_LE;
 
755
#else
 
756
                if (peasycap->microphone)
 
757
                        incoming = AFMT_S16_LE;
 
758
                else
 
759
                        incoming = AFMT_S16_LE;
 
760
#endif /*UPSAMPLE*/
 
761
 
 
762
                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 
763
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
764
                        return -EFAULT;
 
765
                }
 
766
                break;
 
767
        }
 
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);
 
773
                        return -EFAULT;
 
774
                }
 
775
                JOM(8, "........... %i=incoming\n", incoming);
 
776
 
 
777
#ifdef UPSAMPLE
 
778
                if (peasycap->microphone)
 
779
                        outgoing = AFMT_S16_LE;
 
780
                else
 
781
                        outgoing = AFMT_S16_LE;
 
782
#else
 
783
                if (peasycap->microphone)
 
784
                        outgoing = AFMT_S16_LE;
 
785
                else
 
786
                        outgoing = AFMT_S16_LE;
 
787
#endif /*UPSAMPLE*/
 
788
 
 
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);
 
795
                                return -EFAULT;
 
796
                        }
 
797
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
798
                        return -EINVAL ;
 
799
                }
 
800
                break;
 
801
        }
 
802
        case SNDCTL_DSP_STEREO: {
 
803
                int incoming;
 
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);
 
807
                        return -EFAULT;
 
808
                }
 
809
                JOM(8, "........... %i=incoming\n", incoming);
 
810
 
 
811
#ifdef UPSAMPLE
 
812
                if (peasycap->microphone)
 
813
                        incoming = 1;
 
814
                else
 
815
                        incoming = 1;
 
816
#else
 
817
                if (peasycap->microphone)
 
818
                        incoming = 0;
 
819
                else
 
820
                        incoming = 1;
 
821
#endif /*UPSAMPLE*/
 
822
 
 
823
                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 
824
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
825
                        return -EFAULT;
 
826
                }
 
827
                break;
 
828
        }
 
829
        case SNDCTL_DSP_SPEED: {
 
830
                int incoming;
 
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);
 
834
                        return -EFAULT;
 
835
                }
 
836
                JOM(8, "........... %i=incoming\n", incoming);
 
837
 
 
838
#ifdef UPSAMPLE
 
839
                if (peasycap->microphone)
 
840
                        incoming = 32000;
 
841
                else
 
842
                        incoming = 48000;
 
843
#else
 
844
                if (peasycap->microphone)
 
845
                        incoming = 8000;
 
846
                else
 
847
                        incoming = 48000;
 
848
#endif /*UPSAMPLE*/
 
849
 
 
850
                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 
851
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
852
                        return -EFAULT;
 
853
                }
 
854
                break;
 
855
        }
 
856
        case SNDCTL_DSP_GETTRIGGER: {
 
857
                int incoming;
 
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);
 
861
                        return -EFAULT;
 
862
                }
 
863
                JOM(8, "........... %i=incoming\n", incoming);
 
864
 
 
865
                incoming = PCM_ENABLE_INPUT;
 
866
                if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
 
867
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
868
                        return -EFAULT;
 
869
                }
 
870
                break;
 
871
        }
 
872
        case SNDCTL_DSP_SETTRIGGER: {
 
873
                int incoming;
 
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);
 
877
                        return -EFAULT;
 
878
                }
 
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);
 
883
                ;
 
884
                ;
 
885
                ;
 
886
                ;
 
887
                break;
 
888
        }
 
889
        case SNDCTL_DSP_GETBLKSIZE: {
 
890
                int incoming;
 
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);
 
894
                        return -EFAULT;
 
895
                }
 
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);
 
900
                        return -EFAULT;
 
901
                }
 
902
                break;
 
903
        }
 
904
        case SNDCTL_DSP_GETISPACE: {
 
905
                struct audio_buf_info audio_buf_info;
 
906
 
 
907
                JOM(8, "SNDCTL_DSP_GETISPACE\n");
 
908
 
 
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;
 
913
 
 
914
                if (copy_to_user((void __user *)arg, &audio_buf_info, sizeof(int))) {
 
915
                        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
916
                        return -EFAULT;
 
917
                }
 
918
                break;
 
919
        }
 
920
        case 0x00005401:
 
921
        case 0x00005402:
 
922
        case 0x00005403:
 
923
        case 0x00005404:
 
924
        case 0x00005405:
 
925
        case 0x00005406: {
 
926
                JOM(8, "SNDCTL_TMR_...: 0x%08X unsupported\n", cmd);
 
927
                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
928
                return -ENOIOCTLCMD;
 
929
        }
 
930
        default: {
 
931
                JOM(8, "ERROR: unrecognized DSP IOCTL command: 0x%08X\n", cmd);
 
932
                mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
933
                return -ENOIOCTLCMD;
 
934
        }
 
935
        }
 
936
        mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
 
937
        return 0;
 
938
}
 
939
/*****************************************************************************/
 
940
 
 
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,
 
947
        .llseek         = no_llseek,
 
948
};
 
949
struct usb_class_driver easyoss_class = {
 
950
        .name = "usb/easyoss%d",
 
951
        .fops = &easyoss_fops,
 
952
        .minor_base = USB_SKEL_MINOR_BASE,
 
953
};
 
954
/*****************************************************************************/