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