Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
usx2yhwdeppcm.c
Go to the documentation of this file.
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;
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) {
120  usX2Y_iso_frames_per_buffer(runtime, usX2Y);
121  if (0 > 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",
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  }
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)
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 {
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 {
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;
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 
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,
775  64*1024, 128*1024)) ||
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