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