[ALSA] Remove xxx_t typedefs: USB-USX2Y
[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, struct pt_regs *regs)
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((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
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                         if (nr_of_packs() <= urb->start_frame &&
261                             urb->start_frame <= (2 * nr_of_packs() - 1))        // uhci and ohci
262                                 usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
263                         else
264                                 usX2Y->wait_iso_frame +=  nr_of_packs();
265                 } else {
266                         snd_printdd("\n");
267                         usX2Y_clients_stop(usX2Y);
268                 }
269         }
270 }
271
272
273 static void usX2Y_hwdep_urb_release(struct urb **urb)
274 {
275         usb_kill_urb(*urb);
276         usb_free_urb(*urb);
277         *urb = NULL;
278 }
279
280 /*
281  * release a substream
282  */
283 static void usX2Y_usbpcm_urbs_release(struct snd_usX2Y_substream *subs)
284 {
285         int i;
286         snd_printdd("snd_usX2Y_urbs_release() %i\n", subs->endpoint);
287         for (i = 0; i < NRURBS; i++)
288                 usX2Y_hwdep_urb_release(subs->urb + i);
289 }
290
291 static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
292 {
293         usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_urb_complete);
294         usX2Y->prepare_subs = NULL;
295 }
296
297 static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
298 {
299         struct snd_usX2Y_substream *subs = urb->context;
300         struct usX2Ydev *usX2Y = subs->usX2Y;
301         struct snd_usX2Y_substream *prepare_subs = usX2Y->prepare_subs;
302         if (NULL != prepare_subs &&
303             urb->start_frame == prepare_subs->urb[0]->start_frame) {
304                 atomic_inc(&prepare_subs->state);
305                 if (prepare_subs == usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE]) {
306                         struct snd_usX2Y_substream *cap_subs2 = usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
307                         if (cap_subs2 != NULL)
308                                 atomic_inc(&cap_subs2->state);
309                 }
310                 usX2Y_usbpcm_subs_startup_finish(usX2Y);
311                 wake_up(&usX2Y->prepare_wait_queue);
312         }
313
314         i_usX2Y_usbpcm_urb_complete(urb, regs);
315 }
316
317 /*
318  * initialize a substream's urbs
319  */
320 static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs)
321 {
322         int i;
323         unsigned int pipe;
324         int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
325         struct usb_device *dev = subs->usX2Y->chip.dev;
326
327         pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) :
328                         usb_rcvisocpipe(dev, subs->endpoint);
329         subs->maxpacksize = usb_maxpacket(dev, pipe, is_playback);
330         if (!subs->maxpacksize)
331                 return -EINVAL;
332
333         /* allocate and initialize data urbs */
334         for (i = 0; i < NRURBS; i++) {
335                 struct urb **purb = subs->urb + i;
336                 if (*purb) {
337                         usb_kill_urb(*purb);
338                         continue;
339                 }
340                 *purb = usb_alloc_urb(nr_of_packs(), GFP_KERNEL);
341                 if (NULL == *purb) {
342                         usX2Y_usbpcm_urbs_release(subs);
343                         return -ENOMEM;
344                 }
345                 (*purb)->transfer_buffer = is_playback ?
346                         subs->usX2Y->hwdep_pcm_shm->playback : (
347                                 subs->endpoint == 0x8 ?
348                                 subs->usX2Y->hwdep_pcm_shm->capture0x8 :
349                                 subs->usX2Y->hwdep_pcm_shm->capture0xA);
350
351                 (*purb)->dev = dev;
352                 (*purb)->pipe = pipe;
353                 (*purb)->number_of_packets = nr_of_packs();
354                 (*purb)->context = subs;
355                 (*purb)->interval = 1;
356                 (*purb)->complete = i_usX2Y_usbpcm_subs_startup;
357         }
358         return 0;
359 }
360
361 /*
362  * free the buffer
363  */
364 static int snd_usX2Y_usbpcm_hw_free(struct snd_pcm_substream *substream)
365 {
366         struct snd_pcm_runtime *runtime = substream->runtime;
367         struct snd_usX2Y_substream *subs = runtime->private_data,
368                 *cap_subs2 = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE + 2];
369         down(&subs->usX2Y->prepare_mutex);
370         snd_printdd("snd_usX2Y_usbpcm_hw_free(%p)\n", substream);
371
372         if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
373                 struct snd_usX2Y_substream *cap_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
374                 atomic_set(&subs->state, state_STOPPED);
375                 usX2Y_usbpcm_urbs_release(subs);
376                 if (!cap_subs->pcm_substream ||
377                     !cap_subs->pcm_substream->runtime ||
378                     !cap_subs->pcm_substream->runtime->status ||
379                     cap_subs->pcm_substream->runtime->status->state < SNDRV_PCM_STATE_PREPARED) {
380                         atomic_set(&cap_subs->state, state_STOPPED);
381                         if (NULL != cap_subs2)
382                                 atomic_set(&cap_subs2->state, state_STOPPED);
383                         usX2Y_usbpcm_urbs_release(cap_subs);
384                         if (NULL != cap_subs2)
385                                 usX2Y_usbpcm_urbs_release(cap_subs2);
386                 }
387         } else {
388                 struct snd_usX2Y_substream *playback_subs = subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK];
389                 if (atomic_read(&playback_subs->state) < state_PREPARED) {
390                         atomic_set(&subs->state, state_STOPPED);
391                         if (NULL != cap_subs2)
392                                 atomic_set(&cap_subs2->state, state_STOPPED);
393                         usX2Y_usbpcm_urbs_release(subs);
394                         if (NULL != cap_subs2)
395                                 usX2Y_usbpcm_urbs_release(cap_subs2);
396                 }
397         }
398         up(&subs->usX2Y->prepare_mutex);
399         return snd_pcm_lib_free_pages(substream);
400 }
401
402 static void usX2Y_usbpcm_subs_startup(struct snd_usX2Y_substream *subs)
403 {
404         struct usX2Ydev * usX2Y = subs->usX2Y;
405         usX2Y->prepare_subs = subs;
406         subs->urb[0]->start_frame = -1;
407         smp_wmb();      // Make shure above modifications are seen by i_usX2Y_subs_startup()
408         usX2Y_urbs_set_complete(usX2Y, i_usX2Y_usbpcm_subs_startup);
409 }
410
411 static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
412 {
413         int     p, u, err,
414                 stream = subs->pcm_substream->stream;
415         struct usX2Ydev *usX2Y = subs->usX2Y;
416
417         if (SNDRV_PCM_STREAM_CAPTURE == stream) {
418                 usX2Y->hwdep_pcm_shm->captured_iso_head = -1;
419                 usX2Y->hwdep_pcm_shm->captured_iso_frames = 0;
420         }
421
422         for (p = 0; 3 >= (stream + p); p += 2) {
423                 struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
424                 if (subs != NULL) {
425                         if ((err = usX2Y_usbpcm_urbs_allocate(subs)) < 0)
426                                 return err;
427                         subs->completed_urb = NULL;
428                 }
429         }
430
431         for (p = 0; p < 4; p++) {
432                 struct snd_usX2Y_substream *subs = usX2Y->subs[p];
433                 if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
434                         goto start;
435         }
436         usX2Y->wait_iso_frame = -1;
437
438  start:
439         usX2Y_usbpcm_subs_startup(subs);
440         for (u = 0; u < NRURBS; u++) {
441                 for (p = 0; 3 >= (stream + p); p += 2) {
442                         struct snd_usX2Y_substream *subs = usX2Y->subs[stream + p];
443                         if (subs != NULL) {
444                                 struct urb *urb = subs->urb[u];
445                                 if (usb_pipein(urb->pipe)) {
446                                         unsigned long pack;
447                                         if (0 == u)
448                                                 atomic_set(&subs->state, state_STARTING3);
449                                         urb->dev = usX2Y->chip.dev;
450                                         urb->transfer_flags = URB_ISO_ASAP;
451                                         for (pack = 0; pack < nr_of_packs(); pack++) {
452                                                 urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs());
453                                                 urb->iso_frame_desc[pack].length = subs->maxpacksize;
454                                         }
455                                         urb->transfer_buffer_length = subs->maxpacksize * nr_of_packs(); 
456                                         if ((err = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
457                                                 snd_printk (KERN_ERR "cannot usb_submit_urb() for urb %d, err = %d\n", u, err);
458                                                 err = -EPIPE;
459                                                 goto cleanup;
460                                         }  else {
461                                                 snd_printdd("%i\n", urb->start_frame);
462                                                 if (0 > usX2Y->wait_iso_frame)
463                                                         usX2Y->wait_iso_frame = urb->start_frame;
464                                         }
465                                         urb->transfer_flags = 0;
466                                 } else {
467                                         atomic_set(&subs->state, state_STARTING1);
468                                         break;
469                                 }                       
470                         }
471                 }
472         }
473         err = 0;
474         wait_event(usX2Y->prepare_wait_queue, NULL == usX2Y->prepare_subs);
475         if (atomic_read(&subs->state) != state_PREPARED)
476                 err = -EPIPE;
477                 
478  cleanup:
479         if (err) {
480                 usX2Y_subs_startup_finish(usX2Y);       // Call it now
481                 usX2Y_clients_stop(usX2Y);              // something is completely wroong > stop evrything                      
482         }
483         return err;
484 }
485
486 /*
487  * prepare callback
488  *
489  * set format and initialize urbs
490  */
491 static int snd_usX2Y_usbpcm_prepare(struct snd_pcm_substream *substream)
492 {
493         struct snd_pcm_runtime *runtime = substream->runtime;
494         struct snd_usX2Y_substream *subs = runtime->private_data;
495         struct usX2Ydev *usX2Y = subs->usX2Y;
496         struct snd_usX2Y_substream *capsubs = subs->usX2Y->subs[SNDRV_PCM_STREAM_CAPTURE];
497         int err = 0;
498         snd_printdd("snd_usX2Y_pcm_prepare(%p)\n", substream);
499
500         if (NULL == usX2Y->hwdep_pcm_shm) {
501                 if (NULL == (usX2Y->hwdep_pcm_shm = snd_malloc_pages(sizeof(struct snd_usX2Y_hwdep_pcm_shm), GFP_KERNEL)))
502                         return -ENOMEM;
503                 memset(usX2Y->hwdep_pcm_shm, 0, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
504         }
505
506         down(&usX2Y->prepare_mutex);
507         usX2Y_subs_prepare(subs);
508 // Start hardware streams
509 // SyncStream first....
510         if (atomic_read(&capsubs->state) < state_PREPARED) {
511                 if (usX2Y->format != runtime->format)
512                         if ((err = usX2Y_format_set(usX2Y, runtime->format)) < 0)
513                                 goto up_prepare_mutex;
514                 if (usX2Y->rate != runtime->rate)
515                         if ((err = usX2Y_rate_set(usX2Y, runtime->rate)) < 0)
516                                 goto up_prepare_mutex;
517                 snd_printdd("starting capture pipe for %s\n", subs == capsubs ?
518                             "self" : "playpipe");
519                 if (0 > (err = usX2Y_usbpcm_urbs_start(capsubs)))
520                         goto up_prepare_mutex;
521         }
522
523         if (subs != capsubs) {
524                 usX2Y->hwdep_pcm_shm->playback_iso_start = -1;
525                 if (atomic_read(&subs->state) < state_PREPARED) {
526                         while (usX2Y_iso_frames_per_buffer(runtime, usX2Y) >
527                                usX2Y->hwdep_pcm_shm->captured_iso_frames) {
528                                 snd_printdd("Wait: iso_frames_per_buffer=%i,"
529                                             "captured_iso_frames=%i\n",
530                                             usX2Y_iso_frames_per_buffer(runtime, usX2Y),
531                                             usX2Y->hwdep_pcm_shm->captured_iso_frames);
532                                 if (msleep_interruptible(10)) {
533                                         err = -ERESTARTSYS;
534                                         goto up_prepare_mutex;
535                                 }
536                         } 
537                         if (0 > (err = usX2Y_usbpcm_urbs_start(subs)))
538                                 goto up_prepare_mutex;
539                 }
540                 snd_printdd("Ready: iso_frames_per_buffer=%i,captured_iso_frames=%i\n",
541                             usX2Y_iso_frames_per_buffer(runtime, usX2Y),
542                             usX2Y->hwdep_pcm_shm->captured_iso_frames);
543         } else
544                 usX2Y->hwdep_pcm_shm->capture_iso_start = -1;
545
546  up_prepare_mutex:
547         up(&usX2Y->prepare_mutex);
548         return err;
549 }
550
551 static struct snd_pcm_hardware snd_usX2Y_4c =
552 {
553         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
554                                  SNDRV_PCM_INFO_BLOCK_TRANSFER |
555                                  SNDRV_PCM_INFO_MMAP_VALID),
556         .formats =                 SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE,
557         .rates =                   SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
558         .rate_min =                44100,
559         .rate_max =                48000,
560         .channels_min =            2,
561         .channels_max =            4,
562         .buffer_bytes_max =     (2*128*1024),
563         .period_bytes_min =     64,
564         .period_bytes_max =     (128*1024),
565         .periods_min =          2,
566         .periods_max =          1024,
567         .fifo_size =              0
568 };
569
570
571
572 static int snd_usX2Y_usbpcm_open(struct snd_pcm_substream *substream)
573 {
574         struct snd_usX2Y_substream      *subs = ((struct snd_usX2Y_substream **)
575                                          snd_pcm_substream_chip(substream))[substream->stream];
576         struct snd_pcm_runtime  *runtime = substream->runtime;
577
578         if (!(subs->usX2Y->chip_status & USX2Y_STAT_CHIP_MMAP_PCM_URBS))
579                 return -EBUSY;
580
581         runtime->hw = SNDRV_PCM_STREAM_PLAYBACK == substream->stream ? snd_usX2Y_2c :
582                 (subs->usX2Y->subs[3] ? snd_usX2Y_4c : snd_usX2Y_2c);
583         runtime->private_data = subs;
584         subs->pcm_substream = substream;
585         snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000, 200000);
586         return 0;
587 }
588
589
590 static int snd_usX2Y_usbpcm_close(struct snd_pcm_substream *substream)
591 {
592         struct snd_pcm_runtime *runtime = substream->runtime;
593         struct snd_usX2Y_substream *subs = runtime->private_data;
594
595         subs->pcm_substream = NULL;
596         return 0;
597 }
598
599
600 static struct snd_pcm_ops snd_usX2Y_usbpcm_ops = 
601 {
602         .open =         snd_usX2Y_usbpcm_open,
603         .close =        snd_usX2Y_usbpcm_close,
604         .ioctl =        snd_pcm_lib_ioctl,
605         .hw_params =    snd_usX2Y_pcm_hw_params,
606         .hw_free =      snd_usX2Y_usbpcm_hw_free,
607         .prepare =      snd_usX2Y_usbpcm_prepare,
608         .trigger =      snd_usX2Y_pcm_trigger,
609         .pointer =      snd_usX2Y_pcm_pointer,
610 };
611
612
613 static int usX2Y_pcms_lock_check(struct snd_card *card)
614 {
615         struct list_head *list;
616         struct snd_device *dev;
617         struct snd_pcm *pcm;
618         int err = 0;
619         list_for_each(list, &card->devices) {
620                 dev = snd_device(list);
621                 if (dev->type != SNDRV_DEV_PCM)
622                         continue;
623                 pcm = dev->device_data;
624                 down(&pcm->open_mutex);
625         }
626         list_for_each(list, &card->devices) {
627                 int s;
628                 dev = snd_device(list);
629                 if (dev->type != SNDRV_DEV_PCM)
630                         continue;
631                 pcm = dev->device_data;
632                 for (s = 0; s < 2; ++s) {
633                         struct snd_pcm_substream *substream;
634                         substream = pcm->streams[s].substream;
635                         if (substream && substream->ffile != NULL)
636                                 err = -EBUSY;
637                 }
638         }
639         return err;
640 }
641
642
643 static void usX2Y_pcms_unlock(struct snd_card *card)
644 {
645         struct list_head *list;
646         struct snd_device *dev;
647         struct snd_pcm *pcm;
648         list_for_each(list, &card->devices) {
649                 dev = snd_device(list);
650                 if (dev->type != SNDRV_DEV_PCM)
651                         continue;
652                 pcm = dev->device_data;
653                 up(&pcm->open_mutex);
654         }
655 }
656
657
658 static int snd_usX2Y_hwdep_pcm_open(struct snd_hwdep *hw, struct file *file)
659 {
660         // we need to be the first 
661         struct snd_card *card = hw->card;
662         int err = usX2Y_pcms_lock_check(card);
663         if (0 == err)
664                 usX2Y(card)->chip_status |= USX2Y_STAT_CHIP_MMAP_PCM_URBS;
665         usX2Y_pcms_unlock(card);
666         return err;
667 }
668
669
670 static int snd_usX2Y_hwdep_pcm_release(struct snd_hwdep *hw, struct file *file)
671 {
672         struct snd_card *card = hw->card;
673         int err = usX2Y_pcms_lock_check(card);
674         if (0 == err)
675                 usX2Y(hw->card)->chip_status &= ~USX2Y_STAT_CHIP_MMAP_PCM_URBS;
676         usX2Y_pcms_unlock(card);
677         return err;
678 }
679
680
681 static void snd_usX2Y_hwdep_pcm_vm_open(struct vm_area_struct *area)
682 {
683 }
684
685
686 static void snd_usX2Y_hwdep_pcm_vm_close(struct vm_area_struct *area)
687 {
688 }
689
690
691 static struct page * snd_usX2Y_hwdep_pcm_vm_nopage(struct vm_area_struct *area, unsigned long address, int *type)
692 {
693         unsigned long offset;
694         struct page *page;
695         void *vaddr;
696
697         offset = area->vm_pgoff << PAGE_SHIFT;
698         offset += address - area->vm_start;
699         snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM);
700         vaddr = (char*)((struct usX2Ydev *)area->vm_private_data)->hwdep_pcm_shm + offset;
701         page = virt_to_page(vaddr);
702         get_page(page);
703
704         if (type)
705                 *type = VM_FAULT_MINOR;
706
707         return page;
708 }
709
710
711 static struct vm_operations_struct snd_usX2Y_hwdep_pcm_vm_ops = {
712         .open = snd_usX2Y_hwdep_pcm_vm_open,
713         .close = snd_usX2Y_hwdep_pcm_vm_close,
714         .nopage = snd_usX2Y_hwdep_pcm_vm_nopage,
715 };
716
717
718 static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, struct vm_area_struct *area)
719 {
720         unsigned long   size = (unsigned long)(area->vm_end - area->vm_start);
721         struct usX2Ydev *usX2Y = hw->private_data;
722
723         if (!(usX2Y->chip_status & USX2Y_STAT_CHIP_INIT))
724                 return -EBUSY;
725
726         /* if userspace tries to mmap beyond end of our buffer, fail */ 
727         if (size > PAGE_ALIGN(sizeof(struct snd_usX2Y_hwdep_pcm_shm))) {
728                 snd_printd("%lu > %lu\n", size, (unsigned long)sizeof(struct snd_usX2Y_hwdep_pcm_shm)); 
729                 return -EINVAL;
730         }
731
732         if (!usX2Y->hwdep_pcm_shm) {
733                 return -ENODEV;
734         }
735         area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
736         area->vm_flags |= VM_RESERVED;
737         area->vm_private_data = hw->private_data;
738         return 0;
739 }
740
741
742 static void snd_usX2Y_hwdep_pcm_private_free(struct snd_hwdep *hwdep)
743 {
744         struct usX2Ydev *usX2Y = hwdep->private_data;
745         if (NULL != usX2Y->hwdep_pcm_shm)
746                 snd_free_pages(usX2Y->hwdep_pcm_shm, sizeof(struct snd_usX2Y_hwdep_pcm_shm));
747 }
748
749
750 int usX2Y_hwdep_pcm_new(struct snd_card *card)
751 {
752         int err;
753         struct snd_hwdep *hw;
754         struct snd_pcm *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                 return err;
761
762         hw->iface = SNDRV_HWDEP_IFACE_USX2Y_PCM;
763         hw->private_data = usX2Y(card);
764         hw->private_free = snd_usX2Y_hwdep_pcm_private_free;
765         hw->ops.open = snd_usX2Y_hwdep_pcm_open;
766         hw->ops.release = snd_usX2Y_hwdep_pcm_release;
767         hw->ops.mmap = snd_usX2Y_hwdep_pcm_mmap;
768         hw->exclusive = 1;
769         sprintf(hw->name, "/proc/bus/usb/%03d/%03d/hwdeppcm", dev->bus->busnum, dev->devnum);
770
771         err = snd_pcm_new(card, NAME_ALLCAPS" hwdep Audio", 2, 1, 1, &pcm);
772         if (err < 0) {
773                 return err;
774         }
775         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_usX2Y_usbpcm_ops);
776         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usX2Y_usbpcm_ops);
777
778         pcm->private_data = usX2Y(card)->subs;
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                 return err;
791         }
792
793
794         return 0;
795 }
796
797 #else
798
799 int usX2Y_hwdep_pcm_new(struct snd_card *card)
800 {
801         return 0;
802 }
803
804 #endif