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