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

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

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

~ [ 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