Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / sound / usb / usx2y / usx2yhwdeppcm.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
15  */
16
17 /* USX2Y "rawusb" aka hwdep_pcm implementation
18
19  Its usb's unableness to atomically handle power of 2 period sized data chuncs
20  at standard samplerates,
21  what led to this part of the usx2y module: 
22  It provides the alsa kernel half of the usx2y-alsa-jack driver pair.
23  The pair uses a hardware dependant alsa-device for mmaped pcm transport.
24  Advantage achieved:
25          The usb_hc moves pcm data from/into memory via DMA.
26          That memory is mmaped by jack's usx2y driver.
27          Jack's usx2y driver is the first/last to read/write pcm data.
28          Read/write is a combination of power of 2 period shaping and
29          float/int conversation.
30          Compared to mainline alsa/jack we leave out power of 2 period shaping inside
31          snd-usb-usx2y which needs memcpy() and additional buffers.
32          As a side effect possible unwanted pcm-data coruption resulting of
33          standard alsa's snd-usb-usx2y period shaping scheme falls away.
34          Result is sane jack operation at buffering schemes down to 128frames,
35          2 periods.
36          plain usx2y alsa mode is able to achieve 64frames, 4periods, but only at the
37          cost of easier triggered i.e. aeolus xruns (128 or 256frames,
38          2periods works but is useless cause of crackling).
39  
40  This is a first "proof of concept" implementation.
41  Later, funcionalities should migrate to more apropriate places:
42  Userland:
43  - The jackd could mmap its float-pcm buffers directly from alsa-lib.
44  - alsa-lib could provide power of 2 period sized shaping combined with int/float
45    conversation.
46    Currently the usx2y jack driver provides above 2 services.
47  Kernel:
48  - rawusb dma pcm buffer transport should go to snd-usb-lib, so also snd-usb-audio
49    devices can use it.
50    Currently rawusb dma pcm buffer transport (this file) is only available to snd-usb-usx2y. 
51 */
52
53 #include "usbusx2yaudio.c"
54
55 #if defined(USX2Y_NRPACKS_VARIABLE) || (!defined(USX2Y_NRPACKS_VARIABLE) &&  USX2Y_NRPACKS == 1)
56
57 #include <sound/hwdep.h>
58
59
60 static int usX2Y_usbpcm_urb_capt_retire(snd_usX2Y_substream_t *subs)
61 {
62         struct urb      *urb = subs->completed_urb;
63         snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
64         int             i, lens = 0, hwptr_done = subs->hwptr_done;
65         usX2Ydev_t      *usX2Y = subs->usX2Y;
66         if (0 > usX2Y->hwdep_pcm_shm->capture_iso_start) { //FIXME
67                 int head = usX2Y->hwdep_pcm_shm->captured_iso_head + 1;
68                 if (head >= ARRAY_SIZE(usX2Y->hwdep_pcm_shm->captured_iso))
69                         head = 0;
70                 usX2Y->hwdep_pcm_shm->capture_iso_start = head;
71                 snd_printdd("cap start %i\n", head);
72         }
73         for (i = 0; i < nr_of_packs(); i++) {
74                 if (urb->iso_frame_desc[i].status) { /* active? hmm, skip this */
75                         snd_printk("activ frame status %i. Most propably some hardware problem.\n", urb->iso_frame_desc[i].status);
76                         return urb->iso_frame_desc[i].status;
77                 }
78                 lens += urb->iso_frame_desc[i].actual_length / usX2Y->stride;
79         }
80         if ((hwptr_done += lens) >= runtime->buffer_size)
81                 hwptr_done -= runtime->buffer_size;
82         subs->hwptr_done = hwptr_done;
83         subs->transfer_done += lens;
84         /* update the pointer, call callback if necessary */
85         if (subs->transfer_done >= runtime->period_size) {
86                 subs->transfer_done -= runtime->period_size;
87                 snd_pcm_period_elapsed(subs->pcm_substream);
88         }
89         return 0;
90 }
91
92 static inline int usX2Y_iso_frames_per_buffer(snd_pcm_runtime_t *runtime, usX2Ydev_t * usX2Y)
93 {
94         return (runtime->buffer_size * 1000) / usX2Y->rate + 1; //FIXME: so far only correct period_size == 2^x ?
95 }
96
97 /*
98  * prepare urb for playback data pipe
99  *
100  * we copy the data directly from the pcm buffer.
101  * the current position to be copied is held in hwptr field.
102  * since a urb can handle only a single linear buffer, if the total
103  * transferred area overflows the buffer boundary, we cannot send
104  * it directly from the buffer.  thus the data is once copied to
105  * a temporary buffer and urb points to that.
106  */
107 static int usX2Y_hwdep_urb_play_prepare(snd_usX2Y_substream_t *subs,
108                                   struct urb *urb)
109 {
110         int count, counts, pack;
111         usX2Ydev_t *usX2Y = subs->usX2Y;
112         struct snd_usX2Y_hwdep_pcm_shm *shm = usX2Y->hwdep_pcm_shm;
113         snd_pcm_runtime_t *runtime = subs->pcm_substream->runtime;
114
115         if (0 > shm->playback_iso_start) {
116                 shm->playback_iso_start = shm->captured_iso_head -
117                         usX2Y_iso_frames_per_buffer(runtime, usX2Y);
118                 if (0 > shm->playback_iso_start)
119                         shm->playback_iso_start += ARRAY_SIZE(shm->captured_iso);
120                 shm->playback_iso_head = shm->playback_iso_start;
121         }
122
123         count = 0;
124         for (pack = 0; pack < nr_of_packs(); pack++) {
125                 /* calculate the size of a packet */
126                 counts = shm->captured_iso[shm->playback_iso_head].length / usX2Y->stride;
127                 if (counts < 43 || counts > 50) {
128                         snd_printk("should not be here with counts=%i\n", counts);
129                         return -EPIPE;
130                 }
131                 /* set up descriptor */
132                 urb->iso_frame_desc[pack].offset = shm->captured_iso[shm->playback_iso_head].offset;
133                 urb->iso_frame_desc[pack].length = shm->captured_iso[shm->playback_iso_head].length;
134                 if (atomic_read(&subs->state) != state_RUNNING)
135                         memset((char *)urb->transfer_buffer + urb->iso_frame_desc[pack].offset, 0,
136                                urb->iso_frame_desc[pack].length);
137                 if (++shm->playback_iso_head >= ARRAY_SIZE(shm->captured_iso))
138                         shm->playback_iso_head = 0;
139                 count += counts;
140         }
141         urb->transfer_buffer_length = count * usX2Y->stride;
142         return 0;
143 }
144
145
146 static inline void usX2Y_usbpcm_urb_capt_iso_advance(snd_usX2Y_substream_t *subs, struct urb *urb)
147 {
148         int pack;
149         for (pack = 0; pack < nr_of_packs(); ++pack) {
150                 struct usb_iso_packet_descriptor *desc = urb->iso_frame_desc + pack;
151                 if (NULL != subs) {
152                         snd_usX2Y_hwdep_pcm_shm_t *shm = subs->usX2Y->hwdep_pcm_shm;
153                         int head = shm->captured_iso_head + 1;
154                         if (head >= ARRAY_SIZE(shm->captured_iso))
155                                 head = 0;
156                         shm->captured_iso[head].frame = urb->start_frame + pack;
157                         shm->captured_iso[head].offset = desc->offset;
158                         shm->captured_iso[head].length = desc->actual_length;
159                         shm->captured_iso_head = head;
160                         shm->captured_iso_frames++;
161                 }
162                 if ((desc->offset += desc->length * NRURBS*nr_of_packs()) +
163                     desc->length >= SSS)
164                         desc->offset -= (SSS - desc->length);
165         }
166 }
167
168 static inline int usX2Y_usbpcm_usbframe_complete(snd_usX2Y_substream_t *capsubs,
169                                            snd_usX2Y_substream_t *capsubs2,
170                                            snd_usX2Y_substream_t *playbacksubs, int frame)
171 {
172         int err, state;
173         struct urb *urb = playbacksubs->completed_urb;
174
175         state = atomic_read(&playbacksubs->state);
176         if (NULL != urb) {
177                 if (state == state_RUNNING)
178                         usX2Y_urb_play_retire(playbacksubs, urb);
179                 else
180                         if (state >= state_PRERUNNING) {
181                                 atomic_inc(&playbacksubs->state);
182                         }
183         } else {
184                 switch (state) {
185                 case state_STARTING1:
186                         urb = playbacksubs->urb[0];
187                         atomic_inc(&playbacksubs->state);
188                         break;
189                 case state_STARTING2:
190                         urb = playbacksubs->urb[1];
191                         atomic_inc(&playbacksubs->state);
192                         break;
193                 }
194         }
195         if (urb) {
196                 if ((err = usX2Y_hwdep_urb_play_prepare(playbacksubs, urb)) ||
197                     (err = usX2Y_urb_submit(playbacksubs, urb, frame))) {
198                         return err;
199                 }
200         }
201         
202         playbacksubs->completed_urb = NULL;
203
204         state = atomic_read(&capsubs->state);
205         if (state >= state_PREPARED) {
206                 if (state == state_RUNNING) {
207                         if ((err = usX2Y_usbpcm_urb_capt_retire(capsubs)))
208                                 return err;
209                 } else {
210                         if (state >= state_PRERUNNING)
211                                 atomic_inc(&capsubs->state);
212                 }
213                 usX2Y_usbpcm_urb_capt_iso_advance(capsubs, capsubs->completed_urb);
214                 if (NULL != capsubs2)
215                         usX2Y_usbpcm_urb_capt_iso_advance(NULL, capsubs2->completed_urb);
216                 if ((err = usX2Y_urb_submit(capsubs, capsubs->completed_urb, frame)))
217                         return err;
218                 if (NULL != capsubs2)
219                         if ((err = usX2Y_urb_submit(capsubs2, capsubs2->completed_urb, frame)))
220                                 return err;
221         }
222         capsubs->completed_urb = NULL;
223         if (NULL != capsubs2)
224                 capsubs2->completed_urb = NULL;
225         return 0;
226 }
227
228
229 static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
230 {
231         snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
232         usX2Ydev_t *usX2Y = subs->usX2Y;
233         snd_usX2Y_substream_t *capsubs, *capsubs2, *playbacksubs;
234
235         if (unlikely(atomic_read(&subs->state) < state_PREPARED)) {
236                 snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", usb_get_current_frame_number(usX2Y->chip.dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame);
237                 return;
238         }
239         if (unlikely(urb->status)) {
240                 usX2Y_error_urb_status(usX2Y, subs, urb);
241                 return;
242         }
243         if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
244                 subs->completed_urb = urb;
245         else {
246                 usX2Y_error_sequence(usX2Y, subs, urb);
247                 return;
248         }
249
250         capsubs = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
251         capsubs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
252         playbacksubs = usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
253         if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
254             (NULL == capsubs2 || capsubs2->completed_urb) &&
255             (playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
256                 if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
257                         if (nr_of_packs() <= urb->start_frame &&
258                             urb->start_frame <= (2 * nr_of_packs() - 1))        // uhci and ohci
259                                 usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
260                         else
261                                 usX2Y->wait_iso_frame +=  nr_of_packs();
262                 } else {
263                         snd_printdd("\n");
264                         usX2Y_clients_stop(usX2Y);
265                 }
266         }
267 }
268
269
270 static void usX2Y_hwdep_urb_release(struct urb** urb)
271 {
272         usb_kill_urb(*urb);
273         usb_free_urb(*urb);
274         *urb = NULL;
275 }
276
277 /*
278  * release a substream
279  */
280 static void usX2Y_usbpcm_urbs_release(snd_usX2Y_substream_t *subs)
281 {
282         int i;
283         snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
284         for (i = 0; i < NRURBS; i++)
285                 usX2Y_hwdep_urb_release(subs->urb + i);
286 }
287
288 static void usX2Y_usbpcm_subs_startup_finish(usX2Ydev_t * usX2Y)
289 {
290         usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
291         usX2Y->prepare_subs = NULL;
292 }
293
294 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
295 {
296         snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t*)urb->context;
297         usX2Ydev_t *usX2Y = subs->usX2Y;
298         snd_usX2Y_substream_t *prepare_subs = usX2Y->prepare_subs;
299         if (NULL != prepare_subs &&
300             urb->start_frame == prepare_subs->urb[0]->start_frame) {
301                 atomic_inc(&prepare_subs->state);
302                 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
303                         snd_usX2Y_substream_t *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
304                         if (cap_subs2 != NULL)
305                                 atomic_inc(&cap_subs2->state);
306                 }
307                 usX2Y_usbpcm_subs_startup_finish(usX2Y);
308                 wake_up(&usX2Y->prepare_wait_queue);
309         }
310
311         i_usX2Y_usbpcm_urb_complete(urb, regs);
312 }
313
314 /*
315  * initialize a substream's urbs
316  */
317 static int usX2Y_usbpcm_urbs_allocate(snd_usX2Y_substream_t *subs)
318 {
319         int i;
320         unsigned int pipe;
321         int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
322         struct usb_device *dev = subs->usX2Y->chip.dev;
323
324         pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
325                         usb_rcvisocpipe(dev, subs->endpoint);
326         subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
327         if (!subs->maxpacksize)
328                 return -EINVAL;
329
330         /* allocate and initialize data urbs */
331         for (i = 0; i < NRURBS; i++) {
332                 struct urb** purb = subs->urb + i;
333                 if (*purb) {
334                         usb_kill_urb(*purb);
335                         continue;
336                 }
337                 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
338                 if (NULL == *purb) {
339                         usX2Y_usbpcm_urbs_release(subs);
340                         return -ENOMEM;
341                 }
342                 (*purb)->transfer_buffer = is_playback ?
343                         subs->usX2Y->hwdep_pcm_shm->playback : (
344                                 subs->endpoint == 0x8 ?
345                                 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
346                                 subs->usX2Y->hwdep_pcm_shm->capture0xA);
347
348                 (*purb)->dev = dev;
349                 (*purb)->pipe = pipe;
350                 (*purb)->number_of_packets = nr_of_packs();
351                 (*purb)->context = subs;
352                 (*purb)->interval = 1;
353                 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
354         }
355         return 0;
356 }
357
358 /*
359  * free the buffer
360  */
361 static int snd_usX2Y_usbpcm_hw_free(snd_pcm_substream_t *substream)
362 {
363         snd_pcm_runtime_t *runtime = substream->runtime;
364         snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data,
365                 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
366         down(&subs->usX2Y->prepare_mutex);
367         snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
368
369         if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
370                 snd_usX2Y_substream_t *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
371                 atomic_set(&subs->state, state_STOPPED);
372                 usX2Y_usbpcm_urbs_release(subs);
373                 if (!cap_subs->pcm_substream ||
374                     !cap_subs->pcm_substream->runtime ||
375                     !cap_subs->pcm_substream->runtime->status ||
376                     cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
377                         atomic_set(&cap_subs->state, state_STOPPED);
378                         if (NULL != cap_subs2)
379                                 atomic_set(&cap_subs2->state, state_STOPPED);
380                         usX2Y_usbpcm_urbs_release(cap_subs);
381                         if (NULL != cap_subs2)
382                                 usX2Y_usbpcm_urbs_release(cap_subs2);
383                 }
384         } else {
385                 snd_usX2Y_substream_t *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
386                 if (atomic_read(&playback_subs->state) < state_PREPARED) {
387                         atomic_set(&subs->state, state_STOPPED);
388                         if (NULL != cap_subs2)
389                                 atomic_set(&cap_subs2->state, state_STOPPED);
390                         usX2Y_usbpcm_urbs_release(subs);
391                         if (NULL != cap_subs2)
392                                 usX2Y_usbpcm_urbs_release(cap_subs2);
393                 }
394         }
395         up(&subs->usX2Y->prepare_mutex);
396         return snd_pcm_lib_free_pages(substream);
397 }
398
399 static void usX2Y_usbpcm_subs_startup(snd_usX2Y_substream_t *subs)
400 {
401         usX2Ydev_t * usX2Y = subs->usX2Y;
402         usX2Y->prepare_subs = subs;
403         subs->urb[0]->start_frame = -1;
404         smp_wmb();      // Make shure above modifications are seen by i_usX2Y_subs_startup()
405         usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
406 }
407
408 static int usX2Y_usbpcm_urbs_start(snd_usX2Y_substream_t *subs)
409 {
410         int     p, u, err,
411                 stream = subs->pcm_substream->stream;
412         usX2Ydev_t *usX2Y = subs->usX2Y;
413
414         if (SNDRV_PCM_STREAM_CAPTURE == stream) {
415                 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
416                 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
417         }
418
419         for (p = 0; 3 >= (stream + p); p += 2) {
420                 snd_usX2Y_substream_t *subs = usX2Y->subs[stream + p];
421                 if (subs != NULL) {
422                         if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
423                                 return err;
424                         subs->completed_urb = NULL;
425                 }
426         }
427
428         for (p = 0; p < 4; p++) {
429                 snd_usX2Y_substream_t *subs = usX2Y->subs[p];
430                 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
431                         goto start;
432         }
433         usX2Y->wait_iso_frame = -1;
434
435  start:
436         usX2Y_usbpcm_subs_startup(subs);
437         for (u = 0; u < NRURBS; u++) {
438                 for (p = 0; 3 >= (stream + p); p += 2) {
439                         snd_usX2Y_substream_t *subs = usX2Y->subs[stream + p];
440                         if (subs != NULL) {
441                                 struct urb *urb = subs->urb[u];
442                                 if (usb_pipein(urb->pipe)) {
443                                         unsigned long pack;
444                                         if (0 == u)
445                                                 atomic_set(&subs->state, state_STARTING3);
446                                         urb->dev = usX2Y->chip.dev;
447                                         urb->transfer_flags = URB_ISO_ASAP;
448                                         for (pack = 0; pack < nr_of_packs(); pack++) {
449                                                 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
450                                                 urb->iso_frame_desc[pack].length = subs->maxpacksize;
451                                         }
452                                         urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); 
453                                         if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
454                                                 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
455                                                 err = -EPIPE;
456                                                 goto cleanup;
457                                         }  else {
458                                                 snd_printdd("%i\n", urb->start_frame);
459                                                 if (0 > usX2Y->wait_iso_frame)
460                                                         usX2Y->wait_iso_frame = urb->start_frame;
461                                         }
462                                         urb->transfer_flags = 0;
463                                 } else {
464                                         atomic_set(&subs->state, state_STARTING1);
465                                         break;
466                                 }                       
467                         }
468                 }
469         }
470         err = 0;
471         wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
472         if (atomic_read(&subs->state) != state_PREPARED)
473                 err = -EPIPE;
474                 
475  cleanup:
476         if (err) {
477                 usX2Y_subs_startup_finish(usX2Y);       // Call it now
478                 usX2Y_clients_stop(usX2Y);              // something is completely wroong > stop evrything                      
479         }
480         return err;
481 }
482
483 /*
484  * prepare callback
485  *
486  * set format and initialize urbs
487  */
488 static int snd_usX2Y_usbpcm_prepare(snd_pcm_substream_t *substream)
489 {
490         snd_pcm_runtime_t *runtime = substream->runtime;
491         snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
492         usX2Ydev_t *usX2Y = subs->usX2Y;
493         snd_usX2Y_substream_t *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
494         int err = 0;
495         snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
496
497         if (NULL == usX2Y->hwdep_pcm_shm) {
498                 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(snd_usX2Y_hwdep_pcm_shm_t), GFP_KERNEL)))
499                         return -ENOMEM;
500                 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
501         }
502
503         down(&usX2Y->prepare_mutex);
504         usX2Y_subs_prepare(subs);
505 // Start hardware streams
506 // SyncStream first....
507         if (atomic_read(&capsubs->state) < state_PREPARED) {
508                 if (usX2Y->format != runtime->format)
509                         if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
510                                 goto up_prepare_mutex;
511                 if (usX2Y->rate != runtime->rate)
512                         if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
513                                 goto up_prepare_mutex;
514                 snd_printdd("starting capture pipe for %s\n", subs == capsubs ? "self" : "playpipe");
515                 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
516                         goto up_prepare_mutex;
517         }
518
519         if (subs != capsubs) {
520                 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
521                 if (atomic_read(&subs->state) < state_PREPARED) {
522                         while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) > usX2Y->hwdep_pcm_shm->captured_iso_frames) {
523                                 signed long timeout;
524                                 snd_printd("Wait: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames);
525                                 set_current_state(TASK_INTERRUPTIBLE);
526                                 timeout = schedule_timeout(HZ/100 + 1);
527                                 if (signal_pending(current)) {
528                                         err = -ERESTARTSYS;
529                                         goto up_prepare_mutex;
530                                 }
531                         } 
532                         if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
533                                 goto up_prepare_mutex;
534                 }
535                 snd_printd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n", usX2Y_iso_frames_per_buffer(runtime, usX2Y), usX2Y->hwdep_pcm_shm->captured_iso_frames);
536         } else
537                 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
538
539  up_prepare_mutex:
540         up(&usX2Y->prepare_mutex);
541         return err;
542 }
543
544 static snd_pcm_hardware_t snd_usX2Y_4c =
545 {
546         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
547                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
548                                  SNDRV_PCM_INFO_MMAP_VALID),
549         .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
550         .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
551         .rate_min =                44100,
552         .rate_max =                48000,
553         .channels_min =            2,
554         .channels_max =            4,
555         .buffer_bytes_max =     (2*128*1024),
556         .period_bytes_min =     64,
557         .period_bytes_max =     (128*1024),
558         .periods_min =          2,
559         .periods_max =          1024,
560         .fifo_size =              0
561 };
562
563
564
565 static int snd_usX2Y_usbpcm_open(snd_pcm_substream_t *substream)
566 {
567         snd_usX2Y_substream_t   *subs = ((snd_usX2Y_substream_t **)
568                                          snd_pcm_substream_chip(substream))[substream->stream];
569         snd_pcm_runtime_t       *runtime = substream->runtime;
570
571         if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
572                 return -EBUSY;
573
574         runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
575                 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
576         runtime->private_data = subs;
577         subs->pcm_substream = substream;
578         snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
579         return 0;
580 }
581
582
583 static int snd_usX2Y_usbpcm_close(snd_pcm_substream_t *substream)
584 {
585         snd_pcm_runtime_t *runtime = substream->runtime;
586         snd_usX2Y_substream_t *subs = (snd_usX2Y_substream_t *)runtime->private_data;
587         int err = 0;
588         snd_printd("\n");
589         subs->pcm_substream = NULL;
590         return err;
591 }
592
593
594 static snd_pcm_ops_t snd_usX2Y_usbpcm_ops = 
595 {
596         .open =         snd_usX2Y_usbpcm_open,
597         .close =        snd_usX2Y_usbpcm_close,
598         .ioctl =        snd_pcm_lib_ioctl,
599         .hw_params =    snd_usX2Y_pcm_hw_params,
600         .hw_free =      snd_usX2Y_usbpcm_hw_free,
601         .prepare =      snd_usX2Y_usbpcm_prepare,
602         .trigger =      snd_usX2Y_pcm_trigger,
603         .pointer =      snd_usX2Y_pcm_pointer,
604 };
605
606
607 static int usX2Y_pcms_lock_check(snd_card_t *card)
608 {
609         struct list_head *list;
610         snd_device_t *dev;
611         snd_pcm_t *pcm;
612         int err = 0;
613         list_for_each(list, &card->devices) {
614                 dev = snd_device(list);
615                 if (dev->type != SNDRV_DEV_PCM)
616                         continue;
617                 pcm = dev->device_data;
618                 down(&pcm->open_mutex);
619         }
620         list_for_each(list, &card->devices) {
621                 int s;
622                 dev = snd_device(list);
623                 if (dev->type != SNDRV_DEV_PCM)
624                         continue;
625                 pcm = dev->device_data;
626                 for (s = 0; s < 2; ++s) {
627                         snd_pcm_substream_t *substream;
628                         substream = pcm->streams[s].substream;
629                         if (substream && substream->open_flag)
630                                 err = -EBUSY;
631                 }
632         }
633         return err;
634 }
635
636
637 static void usX2Y_pcms_unlock(snd_card_t *card)
638 {
639         struct list_head *list;
640         snd_device_t *dev;
641         snd_pcm_t *pcm;
642         list_for_each(list, &card->devices) {
643                 dev = snd_device(list);
644                 if (dev->type != SNDRV_DEV_PCM)
645                         continue;
646                 pcm = dev->device_data;
647                 up(&pcm->open_mutex);
648         }
649 }
650
651
652 static int snd_usX2Y_hwdep_pcm_open(snd_hwdep_t *hw, struct file *file)
653 {
654         // we need to be the first 
655         snd_card_t *card = hw->card;
656         int err = usX2Y_pcms_lock_check(card);
657         if (0 == err)
658                 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
659         usX2Y_pcms_unlock(card);
660         return err;
661 }
662
663
664 static int snd_usX2Y_hwdep_pcm_release(snd_hwdep_t *hw, struct file *file)
665 {
666         snd_card_t *card = hw->card;
667         int err = usX2Y_pcms_lock_check(card);
668         if (0 == err)
669                 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
670         usX2Y_pcms_unlock(card);
671         return err;
672 }
673
674
675 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
676 {
677 }
678
679
680 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
681 {
682 }
683
684
685 static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
686 {
687         unsigned long offset;
688         struct page *page;
689         void *vaddr;
690
691         offset = area->vm_pgoff << PAGE_SHIFT;
692         offset += address - area->vm_start;
693         snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
694         vaddr = (char*)((usX2Ydev_t*)area->vm_private_data)->hwdep_pcm_shm + offset;
695         page = virt_to_page(vaddr);
696
697         if (type)
698                 *type = VM_FAULT_MINOR;
699
700         return page;
701 }
702
703
704 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
705         .open = snd_usX2Y_hwdep_pcm_vm_open,
706         .close = snd_usX2Y_hwdep_pcm_vm_close,
707         .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,
708 };
709
710
711 static int snd_usX2Y_hwdep_pcm_mmap(snd_hwdep_t * hw, struct file *filp, struct vm_area_struct *area)
712 {
713         unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
714         usX2Ydev_t      *usX2Y = (usX2Ydev_t*)hw->private_data;
715
716         if (!(((usX2Ydev_t*)hw->private_data)->chip_status & USX2Y_STAT_CHIP_INIT))
717                 return -EBUSY;
718
719         /* if userspace tries to mmap beyond end of our buffer, fail */ 
720         if (size > PAGE_ALIGN(sizeof(snd_usX2Y_hwdep_pcm_shm_t))) {
721                 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(snd_usX2Y_hwdep_pcm_shm_t)); 
722                 return -EINVAL;
723         }
724
725         if (!usX2Y->hwdep_pcm_shm) {
726                 return -ENODEV;
727         }
728         area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
729         area->vm_flags |= VM_RESERVED;
730         snd_printd("vm_flags=0x%lX\n", area->vm_flags);
731         area->vm_private_data = hw->private_data;
732         return 0;
733 }
734
735
736 static void snd_usX2Y_hwdep_pcm_private_free(snd_hwdep_t *hwdep)
737 {
738         usX2Ydev_t *usX2Y = (usX2Ydev_t *)hwdep->private_data;
739         if (NULL != usX2Y->hwdep_pcm_shm)
740                 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(snd_usX2Y_hwdep_pcm_shm_t));
741 }
742
743
744 static void snd_usX2Y_usbpcm_private_free(snd_pcm_t *pcm)
745 {
746         snd_pcm_lib_preallocate_free_for_all(pcm);
747 }
748
749
750 int usX2Y_hwdep_pcm_new(snd_card_t* card)
751 {
752         int err;
753         snd_hwdep_t *hw;
754         snd_pcm_t *pcm;
755         struct usb_device *dev = usX2Y(card)->chip.dev;
756         if (1 != nr_of_packs())
757                 return 0;
758
759         if ((err = snd_hwdep_new(card, SND_USX2Y_USBPCM_ID, 1, &hw)) < 0) {
760                 snd_printd("\n");
761                 return err;
762         }
763         hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
764         hw->private_data = usX2Y(card);
765         hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
766         hw->ops.open = snd_usX2Y_hwdep_pcm_open;
767         hw->ops.release = snd_usX2Y_hwdep_pcm_release;
768         hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
769         hw->exclusive = 1;
770         sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
771
772         err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
773         if (err < 0) {
774                 return err;
775         }
776         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
777         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
778
779         pcm->private_data = usX2Y(card)->subs;
780         pcm->private_free = snd_usX2Y_usbpcm_private_free;
781         pcm->info_flags = 0;
782
783         sprintf(pcm->name, NAME_ALLCAPS" hwdep Audio");
784         if (0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream,
785                                                      SNDRV_DMA_TYPE_CONTINUOUS,
786                                                      snd_dma_continuous_data(GFP_KERNEL),
787                                                      64*1024, 128*1024)) ||
788             0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream,
789                                                      SNDRV_DMA_TYPE_CONTINUOUS,
790                                                      snd_dma_continuous_data(GFP_KERNEL),
791                                                      64*1024, 128*1024))) {
792                 snd_usX2Y_usbpcm_private_free(pcm);
793                 return err;
794         }
795
796
797         return 0;
798 }
799
800 #else
801
802 int usX2Y_hwdep_pcm_new(snd_card_t* card)
803 {
804         return 0;
805 }
806
807 #endif