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