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  *  PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
36  */
37 /*--------------------------------------------------------------------------*/
38 static const struct snd_pcm_hardware alsa_hardware = {
39 	.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
40 		SNDRV_PCM_INFO_MMAP           |
41 		SNDRV_PCM_INFO_INTERLEAVED    |
42 		SNDRV_PCM_INFO_MMAP_VALID,
43 	.formats = SNDRV_PCM_FMTBIT_S16_LE,
44 	.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000,
45 	.rate_min = 32000,
46 	.rate_max = 48000,
47 	.channels_min = 2,
48 	.channels_max = 2,
49 	.buffer_bytes_max = PAGE_SIZE *
50 			    PAGES_PER_AUDIO_FRAGMENT *
51 			    AUDIO_FRAGMENT_MANY,
52 	.period_bytes_min = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT,
53 	.period_bytes_max = PAGE_SIZE * PAGES_PER_AUDIO_FRAGMENT * 2,
54 	.periods_min = AUDIO_FRAGMENT_MANY,
55 	.periods_max = AUDIO_FRAGMENT_MANY * 2,
56 };
57 
58 
59 /*---------------------------------------------------------------------------*/
60 /*
61  *  SUBMIT ALL AUDIO URBS.
62  */
63 /*---------------------------------------------------------------------------*/
easycap_audio_submit_urbs(struct easycap * peasycap)64 static int easycap_audio_submit_urbs(struct easycap *peasycap)
65 {
66 	struct data_urb *pdata_urb;
67 	struct urb *purb;
68 	struct list_head *plist_head;
69 	int j, isbad, nospc, m, rc;
70 	int isbuf;
71 
72 	if (!peasycap->purb_audio_head) {
73 		SAM("ERROR: peasycap->urb_audio_head uninitialized\n");
74 		return -EFAULT;
75 	}
76 	if (!peasycap->pusb_device) {
77 		SAM("ERROR: peasycap->pusb_device is NULL\n");
78 		return -EFAULT;
79 	}
80 
81 	if (peasycap->audio_isoc_streaming) {
82 		JOM(4, "already streaming audio urbs\n");
83 		return 0;
84 	}
85 
86 	JOM(4, "initial submission of all audio urbs\n");
87 	rc = usb_set_interface(peasycap->pusb_device,
88 			       peasycap->audio_interface,
89 			       peasycap->audio_altsetting_on);
90 	JOM(8, "usb_set_interface(.,%i,%i) returned %i\n",
91 	    peasycap->audio_interface,
92 	    peasycap->audio_altsetting_on, rc);
93 
94 	isbad = 0;
95 	nospc = 0;
96 	m = 0;
97 	list_for_each(plist_head, peasycap->purb_audio_head) {
98 		pdata_urb = list_entry(plist_head, struct data_urb, list_head);
99 		if (pdata_urb && pdata_urb->purb) {
100 			purb = pdata_urb->purb;
101 			isbuf = pdata_urb->isbuf;
102 
103 			purb->interval = 1;
104 			purb->dev = peasycap->pusb_device;
105 			purb->pipe = usb_rcvisocpipe(peasycap->pusb_device,
106 					peasycap->audio_endpointnumber);
107 			purb->transfer_flags = URB_ISO_ASAP;
108 			purb->transfer_buffer = peasycap->audio_isoc_buffer[isbuf].pgo;
109 			purb->transfer_buffer_length = peasycap->audio_isoc_buffer_size;
110 			purb->complete = easycap_alsa_complete;
111 			purb->context = peasycap;
112 			purb->start_frame = 0;
113 			purb->number_of_packets = peasycap->audio_isoc_framesperdesc;
114 			for (j = 0;  j < peasycap->audio_isoc_framesperdesc; j++) {
115 				purb->iso_frame_desc[j].offset = j * peasycap->audio_isoc_maxframesize;
116 				purb->iso_frame_desc[j].length = peasycap->audio_isoc_maxframesize;
117 			}
118 
119 			rc = usb_submit_urb(purb, GFP_KERNEL);
120 			if (rc) {
121 				isbad++;
122 				SAM("ERROR: usb_submit_urb() failed"
123 				    " for urb with rc: -%s: %d\n",
124 				    strerror(rc), rc);
125 			} else {
126 				m++;
127 			}
128 		} else {
129 			isbad++;
130 		}
131 	}
132 	if (nospc) {
133 		SAM("-ENOSPC=usb_submit_urb() for %i urbs\n", nospc);
134 		SAM(".....  possibly inadequate USB bandwidth\n");
135 		peasycap->audio_eof = 1;
136 	}
137 
138 	if (isbad)
139 		easycap_audio_kill_urbs(peasycap);
140 	else
141 		peasycap->audio_isoc_streaming = m;
142 
143 	return 0;
144 }
145 /*---------------------------------------------------------------------------*/
146 /*
147  *  COMMON AUDIO INITIALIZATION
148  */
149 /*---------------------------------------------------------------------------*/
easycap_sound_setup(struct easycap * peasycap)150 static int easycap_sound_setup(struct easycap *peasycap)
151 {
152 	int rc;
153 
154 	JOM(4, "starting initialization\n");
155 
156 	if (!peasycap) {
157 		SAY("ERROR:  peasycap is NULL.\n");
158 		return -EFAULT;
159 	}
160 	if (!peasycap->pusb_device) {
161 		SAM("ERROR: peasycap->pusb_device is NULL\n");
162 		return -ENODEV;
163 	}
164 	JOM(16, "0x%08lX=peasycap->pusb_device\n", (long int)peasycap->pusb_device);
165 
166 	rc = easycap_audio_setup(peasycap);
167 	JOM(8, "audio_setup() returned %i\n", rc);
168 
169 	if (!peasycap->pusb_device) {
170 		SAM("ERROR: peasycap->pusb_device has become NULL\n");
171 		return -ENODEV;
172 	}
173 /*---------------------------------------------------------------------------*/
174 	if (!peasycap->pusb_device) {
175 		SAM("ERROR: peasycap->pusb_device has become NULL\n");
176 		return -ENODEV;
177 	}
178 	rc = usb_set_interface(peasycap->pusb_device, peasycap->audio_interface,
179 			       peasycap->audio_altsetting_on);
180 	JOM(8, "usb_set_interface(.,%i,%i) returned %i\n", peasycap->audio_interface,
181 	    peasycap->audio_altsetting_on, rc);
182 
183 	rc = easycap_wakeup_device(peasycap->pusb_device);
184 	JOM(8, "wakeup_device() returned %i\n", rc);
185 
186 	peasycap->audio_eof = 0;
187 	peasycap->audio_idle = 0;
188 
189 	easycap_audio_submit_urbs(peasycap);
190 
191 	JOM(4, "finished initialization\n");
192 	return 0;
193 }
194 /*****************************************************************************/
195 /*---------------------------------------------------------------------------*/
196 /*
197  *  ON COMPLETION OF AN AUDIO URB ITS DATA IS COPIED TO THE DAM BUFFER
198  *  PROVIDED peasycap->audio_idle IS ZERO.  REGARDLESS OF THIS BEING TRUE,
199  *  IT IS RESUBMITTED PROVIDED peasycap->audio_isoc_streaming IS NOT ZERO.
200  */
201 /*---------------------------------------------------------------------------*/
easycap_alsa_complete(struct urb * purb)202 void easycap_alsa_complete(struct urb *purb)
203 {
204 	struct easycap *peasycap;
205 	struct snd_pcm_substream *pss;
206 	struct snd_pcm_runtime *prt;
207 	int dma_bytes, fragment_bytes;
208 	int isfragment;
209 	u8 *p1, *p2;
210 	s16 tmp;
211 	int i, j, more, much, rc;
212 #ifdef UPSAMPLE
213 	int k;
214 	s16 oldaudio, newaudio, delta;
215 #endif /*UPSAMPLE*/
216 
217 	JOT(16, "\n");
218 
219 	if (!purb) {
220 		SAY("ERROR: purb is NULL\n");
221 		return;
222 	}
223 	peasycap = purb->context;
224 	if (!peasycap) {
225 		SAY("ERROR: peasycap is NULL\n");
226 		return;
227 	}
228 	much = 0;
229 	if (peasycap->audio_idle) {
230 		JOM(16, "%i=audio_idle  %i=audio_isoc_streaming\n",
231 		    peasycap->audio_idle, peasycap->audio_isoc_streaming);
232 		if (peasycap->audio_isoc_streaming)
233 			goto resubmit;
234 	}
235 /*---------------------------------------------------------------------------*/
236 	pss = peasycap->psubstream;
237 	if (!pss)
238 		goto resubmit;
239 	prt = pss->runtime;
240 	if (!prt)
241 		goto resubmit;
242 	dma_bytes = (int)prt->dma_bytes;
243 	if (0 == dma_bytes)
244 		goto resubmit;
245 	fragment_bytes = 4 * ((int)prt->period_size);
246 	if (0 == fragment_bytes)
247 		goto resubmit;
248 /* -------------------------------------------------------------------------*/
249 	if (purb->status) {
250 		if ((-ESHUTDOWN == purb->status) || (-ENOENT == purb->status)) {
251 			JOM(16, "urb status -ESHUTDOWN or -ENOENT\n");
252 			return;
253 		}
254 		SAM("ERROR: non-zero urb status: -%s: %d\n",
255 		    strerror(purb->status), purb->status);
256 		goto resubmit;
257 	}
258 /*---------------------------------------------------------------------------*/
259 /*
260  *  PROCEED HERE WHEN NO ERROR
261  */
262 /*---------------------------------------------------------------------------*/
263 
264 #ifdef UPSAMPLE
265 	oldaudio = peasycap->oldaudio;
266 #endif /*UPSAMPLE*/
267 
268 	for (i = 0;  i < purb->number_of_packets; i++) {
269 		if (purb->iso_frame_desc[i].status < 0) {
270 			SAM("-%s: %d\n",
271 			    strerror(purb->iso_frame_desc[i].status),
272 			    purb->iso_frame_desc[i].status);
273 		}
274 		if (purb->iso_frame_desc[i].status) {
275 			JOM(12, "discarding audio samples because "
276 			    "%i=purb->iso_frame_desc[i].status\n",
277 			    purb->iso_frame_desc[i].status);
278 			continue;
279 		}
280 		more = purb->iso_frame_desc[i].actual_length;
281 		if (more == 0) {
282 			peasycap->audio_mt++;
283 			continue;
284 		}
285 		if (0 > more) {
286 			SAM("MISTAKE: more is negative\n");
287 			return;
288 		}
289 
290 		if (peasycap->audio_mt) {
291 			JOM(12, "%4i empty audio urb frames\n",
292 			    peasycap->audio_mt);
293 			peasycap->audio_mt = 0;
294 		}
295 
296 		p1 = (u8 *)(purb->transfer_buffer +
297 				purb->iso_frame_desc[i].offset);
298 
299 		/*
300 		 *  COPY more BYTES FROM ISOC BUFFER
301 		 *  TO THE DMA BUFFER, CONVERTING
302 		 *  8-BIT MONO TO 16-BIT SIGNED
303 		 *  LITTLE-ENDIAN SAMPLES IF NECESSARY
304 		 */
305 		while (more) {
306 			much = dma_bytes - peasycap->dma_fill;
307 			if (0 > much) {
308 				SAM("MISTAKE: much is negative\n");
309 				return;
310 			}
311 			if (0 == much) {
312 				peasycap->dma_fill = 0;
313 				peasycap->dma_next = fragment_bytes;
314 				JOM(8, "wrapped dma buffer\n");
315 			}
316 			if (!peasycap->microphone) {
317 				if (much > more)
318 					much = more;
319 				memcpy(prt->dma_area + peasycap->dma_fill,
320 					p1, much);
321 				p1 += much;
322 				more -= much;
323 			} else {
324 #ifdef UPSAMPLE
325 				if (much % 16)
326 					JOM(8, "MISTAKE? much"
327 					    " is not divisible by 16\n");
328 				if (much > (16 * more))
329 					much = 16 * more;
330 				p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
331 
332 				for (j = 0;  j < (much / 16);  j++) {
333 					newaudio =  ((int) *p1) - 128;
334 					newaudio = 128 * newaudio;
335 
336 					delta = (newaudio - oldaudio) / 4;
337 					tmp = oldaudio + delta;
338 
339 					for (k = 0;  k < 4;  k++) {
340 						*p2 = (0x00FF & tmp);
341 						*(p2 + 1) = (0xFF00 & tmp) >> 8;
342 						p2 += 2;
343 						*p2 = (0x00FF & tmp);
344 						*(p2 + 1) = (0xFF00 & tmp) >> 8;
345 						p2 += 2;
346 						tmp += delta;
347 					}
348 					p1++;
349 					more--;
350 					oldaudio = tmp;
351 				}
352 #else /*!UPSAMPLE*/
353 				if (much > (2 * more))
354 					much = 2 * more;
355 				p2 = (u8 *)(prt->dma_area + peasycap->dma_fill);
356 
357 				for (j = 0;  j < (much / 2);  j++) {
358 					tmp = ((int) *p1) - 128;
359 					tmp = 128 * tmp;
360 					*p2 = (0x00FF & tmp);
361 					*(p2 + 1) = (0xFF00 & tmp) >> 8;
362 					p1++;
363 					p2 += 2;
364 					more--;
365 				}
366 #endif /*UPSAMPLE*/
367 			}
368 			peasycap->dma_fill += much;
369 			if (peasycap->dma_fill >= peasycap->dma_next) {
370 				isfragment = peasycap->dma_fill / fragment_bytes;
371 				if (0 > isfragment) {
372 					SAM("MISTAKE: isfragment is negative\n");
373 					return;
374 				}
375 				peasycap->dma_read = (isfragment - 1) * fragment_bytes;
376 				peasycap->dma_next = (isfragment + 1) * fragment_bytes;
377 				if (dma_bytes < peasycap->dma_next)
378 					peasycap->dma_next = fragment_bytes;
379 
380 				if (0 <= peasycap->dma_read) {
381 					JOM(8, "snd_pcm_period_elapsed(), %i="
382 					    "isfragment\n", isfragment);
383 					snd_pcm_period_elapsed(pss);
384 				}
385 			}
386 		}
387 
388 #ifdef UPSAMPLE
389 		peasycap->oldaudio = oldaudio;
390 #endif /*UPSAMPLE*/
391 
392 	}
393 /*---------------------------------------------------------------------------*/
394 /*
395  *  RESUBMIT THIS URB
396  */
397 /*---------------------------------------------------------------------------*/
398 resubmit:
399 	if (peasycap->audio_isoc_streaming == 0)
400 		return;
401 
402 	rc = usb_submit_urb(purb, GFP_ATOMIC);
403 	if (rc) {
404 		if ((-ENODEV != rc) && (-ENOENT != rc)) {
405 			SAM("ERROR: while %i=audio_idle, usb_submit_urb failed "
406 			    "with rc: -%s :%d\n",
407 				peasycap->audio_idle, strerror(rc), rc);
408 		}
409 		if (0 < peasycap->audio_isoc_streaming)
410 			peasycap->audio_isoc_streaming--;
411 	}
412 	return;
413 }
414 /*****************************************************************************/
easycap_alsa_open(struct snd_pcm_substream * pss)415 static int easycap_alsa_open(struct snd_pcm_substream *pss)
416 {
417 	struct snd_pcm *psnd_pcm;
418 	struct snd_card *psnd_card;
419 	struct easycap *peasycap;
420 
421 	JOT(4, "\n");
422 	if (!pss) {
423 		SAY("ERROR:  pss is NULL\n");
424 		return -EFAULT;
425 	}
426 	psnd_pcm = pss->pcm;
427 	if (!psnd_pcm) {
428 		SAY("ERROR:  psnd_pcm is NULL\n");
429 		return -EFAULT;
430 	}
431 	psnd_card = psnd_pcm->card;
432 	if (!psnd_card) {
433 		SAY("ERROR:  psnd_card is NULL\n");
434 		return -EFAULT;
435 	}
436 
437 	peasycap = psnd_card->private_data;
438 	if (!peasycap) {
439 		SAY("ERROR:  peasycap is NULL\n");
440 		return -EFAULT;
441 	}
442 	if (peasycap->psnd_card != psnd_card) {
443 		SAM("ERROR: bad peasycap->psnd_card\n");
444 		return -EFAULT;
445 	}
446 	if (peasycap->psubstream) {
447 		SAM("ERROR: bad peasycap->psubstream\n");
448 		return -EFAULT;
449 	}
450 	pss->private_data = peasycap;
451 	peasycap->psubstream = pss;
452 	pss->runtime->hw = peasycap->alsa_hardware;
453 	pss->runtime->private_data = peasycap;
454 	pss->private_data = peasycap;
455 
456 	if (0 != easycap_sound_setup(peasycap)) {
457 		JOM(4, "ending unsuccessfully\n");
458 		return -EFAULT;
459 	}
460 	JOM(4, "ending successfully\n");
461 	return 0;
462 }
463 /*****************************************************************************/
easycap_alsa_close(struct snd_pcm_substream * pss)464 static int easycap_alsa_close(struct snd_pcm_substream *pss)
465 {
466 	struct easycap *peasycap;
467 
468 	JOT(4, "\n");
469 	if (!pss) {
470 		SAY("ERROR:  pss is NULL\n");
471 		return -EFAULT;
472 	}
473 	peasycap = snd_pcm_substream_chip(pss);
474 	if (!peasycap) {
475 		SAY("ERROR:  peasycap is NULL\n");
476 		return -EFAULT;
477 	}
478 	pss->private_data = NULL;
479 	peasycap->psubstream = NULL;
480 	JOT(4, "ending successfully\n");
481 	return 0;
482 }
483 /*****************************************************************************/
easycap_alsa_vmalloc(struct snd_pcm_substream * pss,size_t sz)484 static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
485 {
486 	struct snd_pcm_runtime *prt;
487 	JOT(4, "\n");
488 
489 	if (!pss) {
490 		SAY("ERROR:  pss is NULL\n");
491 		return -EFAULT;
492 	}
493 	prt = pss->runtime;
494 	if (!prt) {
495 		SAY("ERROR: substream.runtime is NULL\n");
496 		return -EFAULT;
497 	}
498 	if (prt->dma_area) {
499 		if (prt->dma_bytes > sz)
500 			return 0;
501 		vfree(prt->dma_area);
502 	}
503 	prt->dma_area = vmalloc(sz);
504 	if (!prt->dma_area)
505 		return -ENOMEM;
506 	prt->dma_bytes = sz;
507 	return 0;
508 }
509 /*****************************************************************************/
easycap_alsa_hw_params(struct snd_pcm_substream * pss,struct snd_pcm_hw_params * phw)510 static int easycap_alsa_hw_params(struct snd_pcm_substream *pss,
511 				 struct snd_pcm_hw_params *phw)
512 {
513 	int rc;
514 
515 	JOT(4, "%i\n", (params_buffer_bytes(phw)));
516 	if (!pss) {
517 		SAY("ERROR:  pss is NULL\n");
518 		return -EFAULT;
519 	}
520 	rc = easycap_alsa_vmalloc(pss, params_buffer_bytes(phw));
521 	if (rc)
522 		return rc;
523 	return 0;
524 }
525 /*****************************************************************************/
easycap_alsa_hw_free(struct snd_pcm_substream * pss)526 static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
527 {
528 	struct snd_pcm_runtime *prt;
529 	JOT(4, "\n");
530 
531 	if (!pss) {
532 		SAY("ERROR:  pss is NULL\n");
533 		return -EFAULT;
534 	}
535 	prt = pss->runtime;
536 	if (!prt) {
537 		SAY("ERROR: substream.runtime is NULL\n");
538 		return -EFAULT;
539 	}
540 	if (prt->dma_area) {
541 		JOT(8, "prt->dma_area = %p\n", prt->dma_area);
542 		vfree(prt->dma_area);
543 		prt->dma_area = NULL;
544 	} else
545 		JOT(8, "dma_area already freed\n");
546 	return 0;
547 }
548 /*****************************************************************************/
easycap_alsa_prepare(struct snd_pcm_substream * pss)549 static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
550 {
551 	struct easycap *peasycap;
552 	struct snd_pcm_runtime *prt;
553 
554 	JOT(4, "\n");
555 	if (!pss) {
556 		SAY("ERROR:  pss is NULL\n");
557 		return -EFAULT;
558 	}
559 	prt = pss->runtime;
560 	peasycap = snd_pcm_substream_chip(pss);
561 	if (!peasycap) {
562 		SAY("ERROR:  peasycap is NULL\n");
563 		return -EFAULT;
564 	}
565 
566 	JOM(16, "ALSA decides %8i Hz=rate\n", pss->runtime->rate);
567 	JOM(16, "ALSA decides %8ld =period_size\n", pss->runtime->period_size);
568 	JOM(16, "ALSA decides %8i =periods\n", pss->runtime->periods);
569 	JOM(16, "ALSA decides %8ld =buffer_size\n", pss->runtime->buffer_size);
570 	JOM(16, "ALSA decides %8zd =dma_bytes\n", pss->runtime->dma_bytes);
571 	JOM(16, "ALSA decides %8ld =boundary\n", pss->runtime->boundary);
572 	JOM(16, "ALSA decides %8i =period_step\n", pss->runtime->period_step);
573 	JOM(16, "ALSA decides %8i =sample_bits\n", pss->runtime->sample_bits);
574 	JOM(16, "ALSA decides %8i =frame_bits\n", pss->runtime->frame_bits);
575 	JOM(16, "ALSA decides %8ld =min_align\n", pss->runtime->min_align);
576 	JOM(12, "ALSA decides %8ld =hw_ptr_base\n", pss->runtime->hw_ptr_base);
577 	JOM(12, "ALSA decides %8ld =hw_ptr_interrupt\n",
578 		pss->runtime->hw_ptr_interrupt);
579 
580 	if (prt->dma_bytes != 4 * ((int)prt->period_size) * ((int)prt->periods)) {
581 		SAY("MISTAKE:  unexpected ALSA parameters\n");
582 		return -ENOENT;
583 	}
584 	return 0;
585 }
586 /*****************************************************************************/
easycap_alsa_ack(struct snd_pcm_substream * pss)587 static int easycap_alsa_ack(struct snd_pcm_substream *pss)
588 {
589 	return 0;
590 }
591 /*****************************************************************************/
easycap_alsa_trigger(struct snd_pcm_substream * pss,int cmd)592 static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
593 {
594 	struct easycap *peasycap;
595 
596 	JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START,
597 	    SNDRV_PCM_TRIGGER_STOP);
598 	if (!pss) {
599 		SAY("ERROR:  pss is NULL\n");
600 		return -EFAULT;
601 	}
602 	peasycap = snd_pcm_substream_chip(pss);
603 	if (!peasycap) {
604 		SAY("ERROR:  peasycap is NULL\n");
605 		return -EFAULT;
606 	}
607 	switch (cmd) {
608 	case SNDRV_PCM_TRIGGER_START: {
609 		peasycap->audio_idle = 0;
610 		break;
611 	}
612 	case SNDRV_PCM_TRIGGER_STOP: {
613 		peasycap->audio_idle = 1;
614 		break;
615 	}
616 	default:
617 		return -EINVAL;
618 	}
619 	return 0;
620 }
621 /*****************************************************************************/
easycap_alsa_pointer(struct snd_pcm_substream * pss)622 static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
623 {
624 	struct easycap *peasycap;
625 	snd_pcm_uframes_t offset;
626 
627 	JOT(16, "\n");
628 	if (!pss) {
629 		SAY("ERROR:  pss is NULL\n");
630 		return -EFAULT;
631 	}
632 	peasycap = snd_pcm_substream_chip(pss);
633 	if (!peasycap) {
634 		SAY("ERROR:  peasycap is NULL\n");
635 		return -EFAULT;
636 	}
637 	if ((0 != peasycap->audio_eof) || (0 != peasycap->audio_idle)) {
638 		JOM(8, "returning -EIO because  "
639 		    "%i=audio_idle  %i=audio_eof\n",
640 		    peasycap->audio_idle, peasycap->audio_eof);
641 		return -EIO;
642 	}
643 /*---------------------------------------------------------------------------*/
644 	if (0 > peasycap->dma_read) {
645 		JOM(8, "returning -EBUSY\n");
646 		return -EBUSY;
647 	}
648 	offset = ((snd_pcm_uframes_t)peasycap->dma_read)/4;
649 	JOM(8, "ALSA decides %8i   =hw_ptr_base\n", (int)pss->runtime->hw_ptr_base);
650 	JOM(8, "ALSA decides %8i   =hw_ptr_interrupt\n",
651 	    (int)pss->runtime->hw_ptr_interrupt);
652 	JOM(8, "%7i=offset %7i=dma_read %7i=dma_next\n",
653 	    (int)offset, peasycap->dma_read, peasycap->dma_next);
654 	return offset;
655 }
656 /*****************************************************************************/
657 static struct page *
easycap_alsa_page(struct snd_pcm_substream * pss,unsigned long offset)658 easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
659 {
660 	return vmalloc_to_page(pss->runtime->dma_area + offset);
661 }
662 /*****************************************************************************/
663 
664 static struct snd_pcm_ops easycap_alsa_pcm_ops = {
665 	.open      = easycap_alsa_open,
666 	.close     = easycap_alsa_close,
667 	.ioctl     = snd_pcm_lib_ioctl,
668 	.hw_params = easycap_alsa_hw_params,
669 	.hw_free   = easycap_alsa_hw_free,
670 	.prepare   = easycap_alsa_prepare,
671 	.ack       = easycap_alsa_ack,
672 	.trigger   = easycap_alsa_trigger,
673 	.pointer   = easycap_alsa_pointer,
674 	.page      = easycap_alsa_page,
675 };
676 
677 /*****************************************************************************/
678 /*---------------------------------------------------------------------------*/
679 /*
680  *  THE FUNCTION snd_card_create() HAS  THIS_MODULE  AS AN ARGUMENT.  THIS
681  *  MEANS MODULE easycap.  BEWARE.
682 */
683 /*---------------------------------------------------------------------------*/
easycap_alsa_probe(struct easycap * peasycap)684 int easycap_alsa_probe(struct easycap *peasycap)
685 {
686 	int rc;
687 	struct snd_card *psnd_card;
688 	struct snd_pcm *psnd_pcm;
689 
690 	if (!peasycap) {
691 		SAY("ERROR: peasycap is NULL\n");
692 		return -ENODEV;
693 	}
694 	if (0 > peasycap->minor) {
695 		SAY("ERROR: no minor\n");
696 		return -ENODEV;
697 	}
698 
699 	peasycap->alsa_hardware = alsa_hardware;
700 	if (peasycap->microphone) {
701 		peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_32000;
702 		peasycap->alsa_hardware.rate_min = 32000;
703 		peasycap->alsa_hardware.rate_max = 32000;
704 	} else {
705 		peasycap->alsa_hardware.rates = SNDRV_PCM_RATE_48000;
706 		peasycap->alsa_hardware.rate_min = 48000;
707 		peasycap->alsa_hardware.rate_max = 48000;
708 	}
709 
710 	if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa",
711 				THIS_MODULE, 0, &psnd_card)) {
712 		SAY("ERROR: Cannot do ALSA snd_card_create()\n");
713 		return -EFAULT;
714 	}
715 
716 	sprintf(&psnd_card->id[0], "EasyALSA%i", peasycap->minor);
717 	strcpy(&psnd_card->driver[0], EASYCAP_DRIVER_DESCRIPTION);
718 	strcpy(&psnd_card->shortname[0], "easycap_alsa");
719 	sprintf(&psnd_card->longname[0], "%s", &psnd_card->shortname[0]);
720 
721 	psnd_card->dev = &peasycap->pusb_device->dev;
722 	psnd_card->private_data = peasycap;
723 	peasycap->psnd_card = psnd_card;
724 
725 	rc = snd_pcm_new(psnd_card, "easycap_pcm", 0, 0, 1, &psnd_pcm);
726 	if (rc) {
727 		SAM("ERROR: Cannot do ALSA snd_pcm_new()\n");
728 		snd_card_free(psnd_card);
729 		return -EFAULT;
730 	}
731 
732 	snd_pcm_set_ops(psnd_pcm, SNDRV_PCM_STREAM_CAPTURE,
733 			&easycap_alsa_pcm_ops);
734 	psnd_pcm->info_flags = 0;
735 	strcpy(&psnd_pcm->name[0], &psnd_card->id[0]);
736 	psnd_pcm->private_data = peasycap;
737 	peasycap->psnd_pcm = psnd_pcm;
738 	peasycap->psubstream = NULL;
739 
740 	rc = snd_card_register(psnd_card);
741 	if (rc) {
742 		SAM("ERROR: Cannot do ALSA snd_card_register()\n");
743 		snd_card_free(psnd_card);
744 		return -EFAULT;
745 	}
746 
747 	SAM("registered %s\n", &psnd_card->id[0]);
748 	return 0;
749 }
750 
751