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