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