Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/usb/usx2y/usx2yhwdeppcm.c
10817 views
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 "activ frame status %i. Most propably 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_RESERVED | VM_DONTEXPAND;
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
796