Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[deliverable/linux.git] / drivers / staging / media / easycap / easycap_sound.c
CommitLineData
702422bd
T
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"
702422bd 32
a9855917
MT
33/*--------------------------------------------------------------------------*/
34/*
35 * PARAMETERS USED WHEN REGISTERING THE AUDIO INTERFACE
36 */
37/*--------------------------------------------------------------------------*/
38static 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,
a75af077
TW
49 .buffer_bytes_max = PAGE_SIZE *
50 PAGES_PER_AUDIO_FRAGMENT *
51 AUDIO_FRAGMENT_MANY,
a9855917
MT
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
a9855917 58
98680557
TW
59/*---------------------------------------------------------------------------*/
60/*
61 * SUBMIT ALL AUDIO URBS.
62 */
63/*---------------------------------------------------------------------------*/
96bec7dd 64static int easycap_audio_submit_urbs(struct easycap *peasycap)
98680557
TW
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
98680557
TW
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 }
8b1fad2f
TW
137
138 if (isbad)
139 easycap_audio_kill_urbs(peasycap);
140 else
98680557 141 peasycap->audio_isoc_streaming = m;
98680557
TW
142
143 return 0;
144}
145/*---------------------------------------------------------------------------*/
146/*
147 * COMMON AUDIO INITIALIZATION
148 */
149/*---------------------------------------------------------------------------*/
150static 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
96bec7dd 166 rc = easycap_audio_setup(peasycap);
98680557
TW
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
96bec7dd 183 rc = easycap_wakeup_device(peasycap->pusb_device);
98680557
TW
184 JOM(8, "wakeup_device() returned %i\n", rc);
185
186 peasycap->audio_eof = 0;
187 peasycap->audio_idle = 0;
188
96bec7dd 189 easycap_audio_submit_urbs(peasycap);
98680557
TW
190
191 JOM(4, "finished initialization\n");
192 return 0;
193}
a9855917
MT
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/*---------------------------------------------------------------------------*/
96bec7dd 202void easycap_alsa_complete(struct urb *purb)
a9855917 203{
a75af077
TW
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;
3fc0dae8 212#ifdef UPSAMPLE
a75af077
TW
213 int k;
214 s16 oldaudio, newaudio, delta;
a9855917
MT
215#endif /*UPSAMPLE*/
216
a75af077 217 JOT(16, "\n");
a9855917 218
6888393c 219 if (!purb) {
a75af077
TW
220 SAY("ERROR: purb is NULL\n");
221 return;
222 }
223 peasycap = purb->context;
6888393c 224 if (!peasycap) {
a75af077
TW
225 SAY("ERROR: peasycap is NULL\n");
226 return;
227 }
a75af077
TW
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 }
a9855917 235/*---------------------------------------------------------------------------*/
a75af077 236 pss = peasycap->psubstream;
6888393c 237 if (!pss)
a75af077
TW
238 goto resubmit;
239 prt = pss->runtime;
6888393c 240 if (!prt)
a75af077
TW
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;
a9855917 248/* -------------------------------------------------------------------------*/
a75af077
TW
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;
a9855917 257 }
a9855917
MT
258/*---------------------------------------------------------------------------*/
259/*
260 * PROCEED HERE WHEN NO ERROR
261 */
262/*---------------------------------------------------------------------------*/
263
3fc0dae8 264#ifdef UPSAMPLE
a75af077 265 oldaudio = peasycap->oldaudio;
a9855917
MT
266#endif /*UPSAMPLE*/
267
a75af077
TW
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 }
5917def5
TW
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 }
a9855917 289
5917def5
TW
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 {
3fc0dae8 324#ifdef UPSAMPLE
5917def5
TW
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 }
a75af077 352#else /*!UPSAMPLE*/
5917def5
TW
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 }
a9855917 366#endif /*UPSAMPLE*/
5917def5
TW
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);
a9855917
MT
384 }
385 }
386 }
a9855917 387
3fc0dae8 388#ifdef UPSAMPLE
a75af077 389 peasycap->oldaudio = oldaudio;
a9855917
MT
390#endif /*UPSAMPLE*/
391
a75af077 392 }
a9855917
MT
393/*---------------------------------------------------------------------------*/
394/*
395 * RESUBMIT THIS URB
396 */
397/*---------------------------------------------------------------------------*/
398resubmit:
5917def5
TW
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);
a9855917 408 }
5917def5
TW
409 if (0 < peasycap->audio_isoc_streaming)
410 peasycap->audio_isoc_streaming--;
a9855917 411 }
a75af077 412 return;
a9855917
MT
413}
414/*****************************************************************************/
68e4ccaa 415static int easycap_alsa_open(struct snd_pcm_substream *pss)
a9855917 416{
a75af077
TW
417 struct snd_pcm *psnd_pcm;
418 struct snd_card *psnd_card;
419 struct easycap *peasycap;
a9855917 420
a75af077 421 JOT(4, "\n");
6888393c 422 if (!pss) {
a75af077
TW
423 SAY("ERROR: pss is NULL\n");
424 return -EFAULT;
425 }
426 psnd_pcm = pss->pcm;
6888393c 427 if (!psnd_pcm) {
a75af077
TW
428 SAY("ERROR: psnd_pcm is NULL\n");
429 return -EFAULT;
430 }
431 psnd_card = psnd_pcm->card;
6888393c 432 if (!psnd_card) {
a75af077
TW
433 SAY("ERROR: psnd_card is NULL\n");
434 return -EFAULT;
435 }
436
437 peasycap = psnd_card->private_data;
6888393c 438 if (!peasycap) {
a75af077
TW
439 SAY("ERROR: peasycap is NULL\n");
440 return -EFAULT;
441 }
a75af077
TW
442 if (peasycap->psnd_card != psnd_card) {
443 SAM("ERROR: bad peasycap->psnd_card\n");
444 return -EFAULT;
445 }
6888393c 446 if (peasycap->psubstream) {
a75af077
TW
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;
a9855917
MT
462}
463/*****************************************************************************/
68e4ccaa 464static int easycap_alsa_close(struct snd_pcm_substream *pss)
a9855917 465{
a75af077 466 struct easycap *peasycap;
a9855917 467
a75af077 468 JOT(4, "\n");
6888393c 469 if (!pss) {
a75af077
TW
470 SAY("ERROR: pss is NULL\n");
471 return -EFAULT;
472 }
473 peasycap = snd_pcm_substream_chip(pss);
6888393c 474 if (!peasycap) {
a75af077
TW
475 SAY("ERROR: peasycap is NULL\n");
476 return -EFAULT;
477 }
a75af077
TW
478 pss->private_data = NULL;
479 peasycap->psubstream = NULL;
480 JOT(4, "ending successfully\n");
481 return 0;
a9855917
MT
482}
483/*****************************************************************************/
68e4ccaa 484static int easycap_alsa_vmalloc(struct snd_pcm_substream *pss, size_t sz)
a9855917 485{
a75af077
TW
486 struct snd_pcm_runtime *prt;
487 JOT(4, "\n");
a9855917 488
6888393c 489 if (!pss) {
a75af077
TW
490 SAY("ERROR: pss is NULL\n");
491 return -EFAULT;
492 }
493 prt = pss->runtime;
6888393c 494 if (!prt) {
a75af077
TW
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);
6888393c 504 if (!prt->dma_area)
a75af077
TW
505 return -ENOMEM;
506 prt->dma_bytes = sz;
507 return 0;
a9855917
MT
508}
509/*****************************************************************************/
68e4ccaa 510static int easycap_alsa_hw_params(struct snd_pcm_substream *pss,
a75af077 511 struct snd_pcm_hw_params *phw)
68e4ccaa 512{
a75af077 513 int rc;
68e4ccaa 514
a75af077 515 JOT(4, "%i\n", (params_buffer_bytes(phw)));
6888393c 516 if (!pss) {
a75af077
TW
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;
68e4ccaa
TW
524}
525/*****************************************************************************/
526static int easycap_alsa_hw_free(struct snd_pcm_substream *pss)
a9855917 527{
a75af077
TW
528 struct snd_pcm_runtime *prt;
529 JOT(4, "\n");
a9855917 530
6888393c 531 if (!pss) {
a75af077
TW
532 SAY("ERROR: pss is NULL\n");
533 return -EFAULT;
534 }
535 prt = pss->runtime;
6888393c 536 if (!prt) {
a75af077
TW
537 SAY("ERROR: substream.runtime is NULL\n");
538 return -EFAULT;
539 }
6888393c 540 if (prt->dma_area) {
a75af077
TW
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;
a9855917
MT
547}
548/*****************************************************************************/
68e4ccaa 549static int easycap_alsa_prepare(struct snd_pcm_substream *pss)
a9855917 550{
a75af077
TW
551 struct easycap *peasycap;
552 struct snd_pcm_runtime *prt;
a9855917 553
a75af077 554 JOT(4, "\n");
6888393c 555 if (!pss) {
a75af077
TW
556 SAY("ERROR: pss is NULL\n");
557 return -EFAULT;
558 }
559 prt = pss->runtime;
560 peasycap = snd_pcm_substream_chip(pss);
6888393c 561 if (!peasycap) {
a75af077
TW
562 SAY("ERROR: peasycap is NULL\n");
563 return -EFAULT;
564 }
a9855917 565
a75af077
TW
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;
a9855917
MT
585}
586/*****************************************************************************/
68e4ccaa 587static int easycap_alsa_ack(struct snd_pcm_substream *pss)
a9855917 588{
68e4ccaa 589 return 0;
a9855917
MT
590}
591/*****************************************************************************/
68e4ccaa 592static int easycap_alsa_trigger(struct snd_pcm_substream *pss, int cmd)
a9855917 593{
a75af077 594 struct easycap *peasycap;
a9855917 595
a75af077
TW
596 JOT(4, "%i=cmd cf %i=START %i=STOP\n", cmd, SNDRV_PCM_TRIGGER_START,
597 SNDRV_PCM_TRIGGER_STOP);
6888393c 598 if (!pss) {
a75af077
TW
599 SAY("ERROR: pss is NULL\n");
600 return -EFAULT;
601 }
602 peasycap = snd_pcm_substream_chip(pss);
6888393c 603 if (!peasycap) {
a75af077
TW
604 SAY("ERROR: peasycap is NULL\n");
605 return -EFAULT;
606 }
a75af077
TW
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:
a6ff0a06 617 return -EINVAL;
a75af077
TW
618 }
619 return 0;
a9855917
MT
620}
621/*****************************************************************************/
68e4ccaa 622static snd_pcm_uframes_t easycap_alsa_pointer(struct snd_pcm_substream *pss)
a9855917 623{
a75af077
TW
624 struct easycap *peasycap;
625 snd_pcm_uframes_t offset;
a9855917 626
a75af077 627 JOT(16, "\n");
6888393c 628 if (!pss) {
a75af077
TW
629 SAY("ERROR: pss is NULL\n");
630 return -EFAULT;
631 }
632 peasycap = snd_pcm_substream_chip(pss);
6888393c 633 if (!peasycap) {
a75af077
TW
634 SAY("ERROR: peasycap is NULL\n");
635 return -EFAULT;
636 }
a75af077
TW
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 }
a9855917 643/*---------------------------------------------------------------------------*/
a75af077
TW
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;
a9855917
MT
655}
656/*****************************************************************************/
a75af077
TW
657static struct page *
658easycap_alsa_page(struct snd_pcm_substream *pss, unsigned long offset)
a9855917 659{
68e4ccaa 660 return vmalloc_to_page(pss->runtime->dma_area + offset);
a9855917
MT
661}
662/*****************************************************************************/
663
68e4ccaa
TW
664static 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/*---------------------------------------------------------------------------*/
684int easycap_alsa_probe(struct easycap *peasycap)
685{
a75af077
TW
686 int rc;
687 struct snd_card *psnd_card;
688 struct snd_pcm *psnd_pcm;
68e4ccaa 689
6888393c 690 if (!peasycap) {
a75af077
TW
691 SAY("ERROR: peasycap is NULL\n");
692 return -ENODEV;
693 }
a75af077
TW
694 if (0 > peasycap->minor) {
695 SAY("ERROR: no minor\n");
696 return -ENODEV;
697 }
68e4ccaa 698
a75af077 699 peasycap->alsa_hardware = alsa_hardware;
27d683ab 700 if (peasycap->microphone) {
a75af077
TW
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 }
68e4ccaa
TW
709
710 if (0 != snd_card_create(SNDRV_DEFAULT_IDX1, "easycap_alsa",
a75af077 711 THIS_MODULE, 0, &psnd_card)) {
68e4ccaa
TW
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);
6911e7e4 726 if (rc) {
68e4ccaa
TW
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,
a75af077 733 &easycap_alsa_pcm_ops);
68e4ccaa
TW
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;
3c1fb66e 738 peasycap->psubstream = NULL;
68e4ccaa
TW
739
740 rc = snd_card_register(psnd_card);
6911e7e4 741 if (rc) {
68e4ccaa
TW
742 SAM("ERROR: Cannot do ALSA snd_card_register()\n");
743 snd_card_free(psnd_card);
744 return -EFAULT;
68e4ccaa 745 }
5917def5
TW
746
747 SAM("registered %s\n", &psnd_card->id[0]);
a75af077 748 return 0;
68e4ccaa 749}
a9855917 750
This page took 0.226309 seconds and 5 git commands to generate.