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