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