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