PageRenderTime 56ms CodeModel.GetById 17ms app.highlight 29ms RepoModel.GetById 1ms app.codeStats 0ms

/drivers/staging/easycap/easycap_sound_oss.c

https://bitbucket.org/slukk/jb-tsm-kernel-4.2
C | 954 lines | 757 code | 60 blank | 137 comment | 143 complexity | 73121be98a6db40b142e8ad55bd5295c MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
  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/*---------------------------------------------------------------------------*/
 51void
 52easyoss_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/*---------------------------------------------------------------------------*/
253resubmit:
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/*---------------------------------------------------------------------------*/
275static 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/*****************************************************************************/
331static 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/*****************************************************************************/
354static 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/*---------------------------------------------------------------------------*/
650static 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
941static 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};
949struct usb_class_driver easyoss_class = {
950	.name = "usb/easyoss%d",
951	.fops = &easyoss_fops,
952	.minor_base = USB_SKEL_MINOR_BASE,
953};
954/*****************************************************************************/