staging/easycap: remove unused macro MICROSECONDS
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / easycap / easycap_sound_oss.c
blobd92baf2227659bf3fc04d54576a26da7d8d865c8
1 /******************************************************************************
2 * *
3 * easycap_sound.c *
4 * *
5 * Audio driver for EasyCAP USB2.0 Video Capture Device DC60 *
6 * *
7 * *
8 ******************************************************************************/
9 /*
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 /*****************************************************************************/
31 #include "easycap.h"
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 /*---------------------------------------------------------------------------*/
51 void
52 easyoss_complete(struct urb *purb)
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*/
64 JOT(16, "\n");
66 if (!purb) {
67 SAY("ERROR: purb is NULL\n");
68 return;
70 peasycap = purb->context;
71 if (!peasycap) {
72 SAY("ERROR: peasycap is NULL\n");
73 return;
75 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
76 SAY("ERROR: bad peasycap\n");
77 return;
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);
94 return;
96 /*---------------------------------------------------------------------------*/
97 if (purb->status) {
98 if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
99 JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
100 return;
102 SAM("ERROR: non-zero urb status: -%s: %d\n",
103 strerror(purb->status), purb->status);
104 goto resubmit;
106 /*---------------------------------------------------------------------------*/
108 * PROCEED HERE WHEN NO ERROR
110 /*---------------------------------------------------------------------------*/
111 #ifdef UPSAMPLE
112 oldaudio = peasycap->oldaudio;
113 #endif /*UPSAMPLE*/
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;
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;
131 p1 = (u8 *)(purb->transfer_buffer + purb->iso_frame_desc[i].offset);
133 leap = 0;
134 p1 += leap;
135 more -= leap;
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
142 while (more) {
143 if (0 > more) {
144 SAM("MISTAKE: more is negative\n");
145 return;
147 if (peasycap->audio_buffer_page_many <= peasycap->audio_fill) {
148 SAM("ERROR: bad peasycap->audio_fill\n");
149 return;
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;
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) {
182 if (much > more)
183 much = more;
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;
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;
207 p2 += 2;
208 *p2 = (0x00FF & tmp);
209 *(p2 + 1) = (0xFF00 & tmp) >> 8;
210 p2 += 2;
212 tmp += delta;
214 p1++;
215 more--;
216 oldaudio = tmp;
218 #else /*!UPSAMPLE*/
219 if (much > (2 * more))
220 much = 2 * more;
221 p2 = (u8 *)paudio_buffer->pto;
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--;
232 #endif /*UPSAMPLE*/
234 (paudio_buffer->pto) += much;
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);
243 #ifdef UPSAMPLE
244 peasycap->oldaudio = oldaudio;
245 #endif /*UPSAMPLE*/
248 /*---------------------------------------------------------------------------*/
250 * RESUBMIT THIS URB
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);
265 return;
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;
279 int subminor;
280 struct v4l2_device *pv4l2_device;
282 JOT(4, "begins\n");
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");
290 return -1;
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;
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);
308 if (!pv4l2_device) {
309 SAY("ERROR: pv4l2_device is NULL\n");
310 return -EFAULT;
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);
318 return -EFAULT;
320 /*---------------------------------------------------------------------------*/
322 file->private_data = peasycap;
324 if (0 != easycap_sound_setup(peasycap)) {
328 return 0;
330 /*****************************************************************************/
331 static int easyoss_release(struct inode *inode, struct file *file)
333 struct easycap *peasycap;
335 JOT(4, "begins\n");
337 peasycap = file->private_data;
338 if (!peasycap) {
339 SAY("ERROR: peasycap is NULL.\n");
340 return -EFAULT;
342 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
343 SAY("ERROR: bad peasycap: %p\n", peasycap);
344 return -EFAULT;
346 if (0 != kill_audio_urbs(peasycap)) {
347 SAM("ERROR: kill_audio_urbs() failed\n");
348 return -EFAULT;
350 JOM(4, "ending successfully\n");
351 return 0;
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;
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;
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);
380 if (!file) {
381 SAY("ERROR: file is NULL\n");
382 return -ERESTARTSYS;
384 peasycap = file->private_data;
385 if (!peasycap) {
386 SAY("ERROR in easyoss_read(): peasycap is NULL\n");
387 return -EFAULT;
389 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
390 SAY("ERROR: bad peasycap: %p\n", peasycap);
391 return -EFAULT;
393 if (!peasycap->pusb_device) {
394 SAY("ERROR: peasycap->pusb_device is NULL\n");
395 return -EFAULT;
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;
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))
412 return -ERESTARTSYS;
413 if (!file) {
414 SAY("ERROR: file is NULL\n");
415 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
416 return -ERESTARTSYS;
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;
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;
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;
434 } else {
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.
441 return -ERESTARTSYS;
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);
451 return -EFAULT;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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);
528 if (fragment != (peasycap->audio_read / peasycap->audio_pages_per_fragment))
529 break;
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;
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;
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;
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;
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);
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;
566 * ACCUMULATE DYNAMIC-RANGE INFORMATION
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;
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;
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));
594 if (kount < 0) {
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;
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);
635 if (below)
636 sdr = signed_div(above, below);
637 else
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);
646 return 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;
655 int kd;
657 if (!file) {
658 SAY("ERROR: file is NULL\n");
659 return -ERESTARTSYS;
661 peasycap = file->private_data;
662 if (!peasycap) {
663 SAY("ERROR: peasycap is NULL.\n");
664 return -EFAULT;
666 if (memcmp(&peasycap->telltale[0], TELLTALE, strlen(TELLTALE))) {
667 SAY("ERROR: bad peasycap\n");
668 return -EFAULT;
670 p = peasycap->pusb_device;
671 if (!p) {
672 SAM("ERROR: peasycap->pusb_device is NULL\n");
673 return -EFAULT;
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;
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))
690 return -ERESTARTSYS;
691 if (!file) {
692 SAY("ERROR: file is NULL\n");
693 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
694 return -ERESTARTSYS;
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;
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;
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;
713 } else {
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.
720 return -ERESTARTSYS;
722 /*---------------------------------------------------------------------------*/
723 switch (cmd) {
724 case SNDCTL_DSP_GETCAPS: {
725 int caps;
726 JOM(8, "SNDCTL_DSP_GETCAPS\n");
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*/
740 if (copy_to_user((void __user *)arg, &caps, sizeof(int))) {
741 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
742 return -EFAULT;
744 break;
746 case SNDCTL_DSP_GETFMTS: {
747 int incoming;
748 JOM(8, "SNDCTL_DSP_GETFMTS\n");
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*/
762 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
763 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
764 return -EFAULT;
766 break;
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;
775 JOM(8, "........... %i=incoming\n", incoming);
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*/
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;
797 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
798 return -EINVAL ;
800 break;
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;
809 JOM(8, "........... %i=incoming\n", incoming);
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*/
823 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
824 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
825 return -EFAULT;
827 break;
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;
836 JOM(8, "........... %i=incoming\n", incoming);
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*/
850 if (copy_to_user((void __user *)arg, &incoming, sizeof(int))) {
851 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
852 return -EFAULT;
854 break;
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;
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);
868 return -EFAULT;
870 break;
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;
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);
887 break;
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;
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;
902 break;
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);
916 return -EFAULT;
918 break;
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;
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;
936 mutex_unlock(&easycapdc60_dongle[kd].mutex_audio);
937 return 0;
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,
947 .llseek = no_llseek,
949 struct usb_class_driver easyoss_class = {
950 .name = "usb/easyoss%d",
951 .fops = &easyoss_fops,
952 .minor_base = USB_SKEL_MINOR_BASE,
954 /*****************************************************************************/