~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/usb/usx2y/usx2yhwdeppcm.c

Version: ~ [ linux-5.6-rc3 ] ~ [ linux-5.5.6 ] ~ [ linux-5.4.22 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.106 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.171 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.214 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.214 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp