OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [sound/] [usb/] [usx2y/] [usx2yhwdeppcm.c] - Blame information for rev 3

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.