aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb/6fire/pcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb/6fire/pcm.c')
-rw-r--r--sound/usb/6fire/pcm.c688
1 files changed, 688 insertions, 0 deletions
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
new file mode 100644
index 000000000000..ba62c7468ba8
--- /dev/null
+++ b/sound/usb/6fire/pcm.c
@@ -0,0 +1,688 @@
1/*
2 * Linux driver for TerraTec DMX 6Fire USB
3 *
4 * PCM driver
5 *
6 * Author: Torsten Schenk <torsten.schenk@zoho.com>
7 * Created: Jan 01, 2011
8 * Version: 0.3.0
9 * Copyright: (C) Torsten Schenk
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 */
16
17#include "pcm.h"
18#include "chip.h"
19#include "comm.h"
20
21enum {
22 OUT_N_CHANNELS = 6, IN_N_CHANNELS = 4
23};
24
25/* keep next two synced with
26 * FW_EP_W_MAX_PACKET_SIZE[] and RATES_MAX_PACKET_SIZE */
27static const int rates_in_packet_size[] = { 228, 228, 420, 420, 404, 404 };
28static const int rates_out_packet_size[] = { 228, 228, 420, 420, 604, 604 };
29static const int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000 };
30static const int rates_altsetting[] = { 1, 1, 2, 2, 3, 3 };
31static const int rates_alsaid[] = {
32 SNDRV_PCM_RATE_44100, SNDRV_PCM_RATE_48000,
33 SNDRV_PCM_RATE_88200, SNDRV_PCM_RATE_96000,
34 SNDRV_PCM_RATE_176400, SNDRV_PCM_RATE_192000 };
35
36/* values to write to soundcard register for all samplerates */
37static const u16 rates_6fire_vl[] = {0x00, 0x01, 0x00, 0x01, 0x00, 0x01};
38static const u16 rates_6fire_vh[] = {0x11, 0x11, 0x10, 0x10, 0x00, 0x00};
39
40enum { /* settings for pcm */
41 OUT_EP = 6, IN_EP = 2, MAX_BUFSIZE = 128 * 1024
42};
43
44enum { /* pcm streaming states */
45 STREAM_DISABLED, /* no pcm streaming */
46 STREAM_STARTING, /* pcm streaming requested, waiting to become ready */
47 STREAM_RUNNING, /* pcm streaming running */
48 STREAM_STOPPING
49};
50
51enum { /* pcm sample rates (also index into RATES_XXX[]) */
52 RATE_44KHZ,
53 RATE_48KHZ,
54 RATE_88KHZ,
55 RATE_96KHZ,
56 RATE_176KHZ,
57 RATE_192KHZ
58};
59
60static const struct snd_pcm_hardware pcm_hw = {
61 .info = SNDRV_PCM_INFO_MMAP |
62 SNDRV_PCM_INFO_INTERLEAVED |
63 SNDRV_PCM_INFO_BLOCK_TRANSFER |
64 SNDRV_PCM_INFO_MMAP_VALID |
65 SNDRV_PCM_INFO_BATCH,
66
67 .formats = SNDRV_PCM_FMTBIT_S24_LE,
68
69 .rates = SNDRV_PCM_RATE_44100 |
70 SNDRV_PCM_RATE_48000 |
71 SNDRV_PCM_RATE_88200 |
72 SNDRV_PCM_RATE_96000 |
73 SNDRV_PCM_RATE_176400 |
74 SNDRV_PCM_RATE_192000,
75
76 .rate_min = 44100,
77 .rate_max = 192000,
78 .channels_min = 1,
79 .channels_max = 0, /* set in pcm_open, depending on capture/playback */
80 .buffer_bytes_max = MAX_BUFSIZE,
81 .period_bytes_min = PCM_N_PACKETS_PER_URB * (PCM_MAX_PACKET_SIZE - 4),
82 .period_bytes_max = MAX_BUFSIZE,
83 .periods_min = 2,
84 .periods_max = 1024
85};
86
87static int usb6fire_pcm_set_rate(struct pcm_runtime *rt)
88{
89 int ret;
90 struct usb_device *device = rt->chip->dev;
91 struct comm_runtime *comm_rt = rt->chip->comm;
92
93 if (rt->rate >= ARRAY_SIZE(rates))
94 return -EINVAL;
95 /* disable streaming */
96 ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x00);
97 if (ret < 0) {
98 snd_printk(KERN_ERR PREFIX "error stopping streaming while "
99 "setting samplerate %d.\n", rates[rt->rate]);
100 return ret;
101 }
102
103 ret = usb_set_interface(device, 1, rates_altsetting[rt->rate]);
104 if (ret < 0) {
105 snd_printk(KERN_ERR PREFIX "error setting interface "
106 "altsetting %d for samplerate %d.\n",
107 rates_altsetting[rt->rate], rates[rt->rate]);
108 return ret;
109 }
110
111 /* set soundcard clock */
112 ret = comm_rt->write16(comm_rt, 0x02, 0x01, rates_6fire_vl[rt->rate],
113 rates_6fire_vh[rt->rate]);
114 if (ret < 0) {
115 snd_printk(KERN_ERR PREFIX "error setting samplerate %d.\n",
116 rates[rt->rate]);
117 return ret;
118 }
119
120 /* enable analog inputs and outputs
121 * (one bit per stereo-channel) */
122 ret = comm_rt->write16(comm_rt, 0x02, 0x02,
123 (1 << (OUT_N_CHANNELS / 2)) - 1,
124 (1 << (IN_N_CHANNELS / 2)) - 1);
125 if (ret < 0) {
126 snd_printk(KERN_ERR PREFIX "error initializing analog channels "
127 "while setting samplerate %d.\n",
128 rates[rt->rate]);
129 return ret;
130 }
131 /* disable digital inputs and outputs */
132 ret = comm_rt->write16(comm_rt, 0x02, 0x03, 0x00, 0x00);
133 if (ret < 0) {
134 snd_printk(KERN_ERR PREFIX "error initializing digital "
135 "channels while setting samplerate %d.\n",
136 rates[rt->rate]);
137 return ret;
138 }
139
140 ret = comm_rt->write16(comm_rt, 0x02, 0x00, 0x00, 0x01);
141 if (ret < 0) {
142 snd_printk(KERN_ERR PREFIX "error starting streaming while "
143 "setting samplerate %d.\n", rates[rt->rate]);
144 return ret;
145 }
146
147 rt->in_n_analog = IN_N_CHANNELS;
148 rt->out_n_analog = OUT_N_CHANNELS;
149 rt->in_packet_size = rates_in_packet_size[rt->rate];
150 rt->out_packet_size = rates_out_packet_size[rt->rate];
151 return 0;
152}
153
154static struct pcm_substream *usb6fire_pcm_get_substream(
155 struct snd_pcm_substream *alsa_sub)
156{
157 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
158
159 if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK)
160 return &rt->playback;
161 else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE)
162 return &rt->capture;
163 snd_printk(KERN_ERR PREFIX "error getting pcm substream slot.\n");
164 return NULL;
165}
166
167/* call with stream_mutex locked */
168static void usb6fire_pcm_stream_stop(struct pcm_runtime *rt)
169{
170 int i;
171
172 if (rt->stream_state != STREAM_DISABLED) {
173 for (i = 0; i < PCM_N_URBS; i++) {
174 usb_kill_urb(&rt->in_urbs[i].instance);
175 usb_kill_urb(&rt->out_urbs[i].instance);
176 }
177 rt->stream_state = STREAM_DISABLED;
178 }
179}
180
181/* call with stream_mutex locked */
182static int usb6fire_pcm_stream_start(struct pcm_runtime *rt)
183{
184 int ret;
185 int i;
186 int k;
187 struct usb_iso_packet_descriptor *packet;
188
189 if (rt->stream_state == STREAM_DISABLED) {
190 /* submit our in urbs */
191 rt->stream_wait_cond = false;
192 rt->stream_state = STREAM_STARTING;
193 for (i = 0; i < PCM_N_URBS; i++) {
194 for (k = 0; k < PCM_N_PACKETS_PER_URB; k++) {
195 packet = &rt->in_urbs[i].packets[k];
196 packet->offset = k * rt->in_packet_size;
197 packet->length = rt->in_packet_size;
198 packet->actual_length = 0;
199 packet->status = 0;
200 }
201 ret = usb_submit_urb(&rt->in_urbs[i].instance,
202 GFP_ATOMIC);
203 if (ret) {
204 usb6fire_pcm_stream_stop(rt);
205 return ret;
206 }
207 }
208
209 /* wait for first out urb to return (sent in in urb handler) */
210 wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond,
211 HZ);
212 if (rt->stream_wait_cond)
213 rt->stream_state = STREAM_RUNNING;
214 else {
215 usb6fire_pcm_stream_stop(rt);
216 return -EIO;
217 }
218 }
219 return 0;
220}
221
222/* call with substream locked */
223static void usb6fire_pcm_capture(struct pcm_substream *sub, struct pcm_urb *urb)
224{
225 int i;
226 int frame;
227 int frame_count;
228 unsigned int total_length = 0;
229 struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
230 struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
231 u32 *src = (u32 *) urb->buffer;
232 u32 *dest = (u32 *) (alsa_rt->dma_area + sub->dma_off
233 * (alsa_rt->frame_bits >> 3));
234 u32 *dest_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
235 * (alsa_rt->frame_bits >> 3));
236 int bytes_per_frame = alsa_rt->channels << 2;
237
238 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
239 /* at least 4 header bytes for valid packet.
240 * after that: 32 bits per sample for analog channels */
241 if (urb->packets[i].actual_length > 4)
242 frame_count = (urb->packets[i].actual_length - 4)
243 / (rt->in_n_analog << 2);
244 else
245 frame_count = 0;
246
247 src = (u32 *) (urb->buffer + total_length);
248 src++; /* skip leading 4 bytes of every packet */
249 total_length += urb->packets[i].length;
250 for (frame = 0; frame < frame_count; frame++) {
251 memcpy(dest, src, bytes_per_frame);
252 dest += alsa_rt->channels;
253 src += rt->in_n_analog;
254 sub->dma_off++;
255 sub->period_off++;
256 if (dest == dest_end) {
257 sub->dma_off = 0;
258 dest = (u32 *) alsa_rt->dma_area;
259 }
260 }
261 }
262}
263
264/* call with substream locked */
265static void usb6fire_pcm_playback(struct pcm_substream *sub,
266 struct pcm_urb *urb)
267{
268 int i;
269 int frame;
270 int frame_count;
271 struct pcm_runtime *rt = snd_pcm_substream_chip(sub->instance);
272 struct snd_pcm_runtime *alsa_rt = sub->instance->runtime;
273 u32 *src = (u32 *) (alsa_rt->dma_area + sub->dma_off
274 * (alsa_rt->frame_bits >> 3));
275 u32 *src_end = (u32 *) (alsa_rt->dma_area + alsa_rt->buffer_size
276 * (alsa_rt->frame_bits >> 3));
277 u32 *dest = (u32 *) urb->buffer;
278 int bytes_per_frame = alsa_rt->channels << 2;
279
280 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
281 /* at least 4 header bytes for valid packet.
282 * after that: 32 bits per sample for analog channels */
283 if (urb->packets[i].length > 4)
284 frame_count = (urb->packets[i].length - 4)
285 / (rt->out_n_analog << 2);
286 else
287 frame_count = 0;
288 dest++; /* skip leading 4 bytes of every frame */
289 for (frame = 0; frame < frame_count; frame++) {
290 memcpy(dest, src, bytes_per_frame);
291 src += alsa_rt->channels;
292 dest += rt->out_n_analog;
293 sub->dma_off++;
294 sub->period_off++;
295 if (src == src_end) {
296 src = (u32 *) alsa_rt->dma_area;
297 sub->dma_off = 0;
298 }
299 }
300 }
301}
302
303static void usb6fire_pcm_in_urb_handler(struct urb *usb_urb)
304{
305 struct pcm_urb *in_urb = usb_urb->context;
306 struct pcm_urb *out_urb = in_urb->peer;
307 struct pcm_runtime *rt = in_urb->chip->pcm;
308 struct pcm_substream *sub;
309 unsigned long flags;
310 int total_length = 0;
311 int frame_count;
312 int frame;
313 int channel;
314 int i;
315 u8 *dest;
316
317 if (usb_urb->status || rt->panic || rt->stream_state == STREAM_STOPPING)
318 return;
319 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)
320 if (in_urb->packets[i].status) {
321 rt->panic = true;
322 return;
323 }
324
325 if (rt->stream_state == STREAM_DISABLED) {
326 snd_printk(KERN_ERR PREFIX "internal error: "
327 "stream disabled in in-urb handler.\n");
328 return;
329 }
330
331 /* receive our capture data */
332 sub = &rt->capture;
333 spin_lock_irqsave(&sub->lock, flags);
334 if (sub->active) {
335 usb6fire_pcm_capture(sub, in_urb);
336 if (sub->period_off >= sub->instance->runtime->period_size) {
337 sub->period_off %= sub->instance->runtime->period_size;
338 spin_unlock_irqrestore(&sub->lock, flags);
339 snd_pcm_period_elapsed(sub->instance);
340 } else
341 spin_unlock_irqrestore(&sub->lock, flags);
342 } else
343 spin_unlock_irqrestore(&sub->lock, flags);
344
345 /* setup out urb structure */
346 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++) {
347 out_urb->packets[i].offset = total_length;
348 out_urb->packets[i].length = (in_urb->packets[i].actual_length
349 - 4) / (rt->in_n_analog << 2)
350 * (rt->out_n_analog << 2) + 4;
351 out_urb->packets[i].status = 0;
352 total_length += out_urb->packets[i].length;
353 }
354 memset(out_urb->buffer, 0, total_length);
355
356 /* now send our playback data (if a free out urb was found) */
357 sub = &rt->playback;
358 spin_lock_irqsave(&sub->lock, flags);
359 if (sub->active) {
360 usb6fire_pcm_playback(sub, out_urb);
361 if (sub->period_off >= sub->instance->runtime->period_size) {
362 sub->period_off %= sub->instance->runtime->period_size;
363 spin_unlock_irqrestore(&sub->lock, flags);
364 snd_pcm_period_elapsed(sub->instance);
365 } else
366 spin_unlock_irqrestore(&sub->lock, flags);
367 } else
368 spin_unlock_irqrestore(&sub->lock, flags);
369
370 /* setup the 4th byte of each sample (0x40 for analog channels) */
371 dest = out_urb->buffer;
372 for (i = 0; i < PCM_N_PACKETS_PER_URB; i++)
373 if (out_urb->packets[i].length >= 4) {
374 frame_count = (out_urb->packets[i].length - 4)
375 / (rt->out_n_analog << 2);
376 *(dest++) = 0xaa;
377 *(dest++) = 0xaa;
378 *(dest++) = frame_count;
379 *(dest++) = 0x00;
380 for (frame = 0; frame < frame_count; frame++)
381 for (channel = 0;
382 channel < rt->out_n_analog;
383 channel++) {
384 dest += 3; /* skip sample data */
385 *(dest++) = 0x40;
386 }
387 }
388 usb_submit_urb(&out_urb->instance, GFP_ATOMIC);
389 usb_submit_urb(&in_urb->instance, GFP_ATOMIC);
390}
391
392static void usb6fire_pcm_out_urb_handler(struct urb *usb_urb)
393{
394 struct pcm_urb *urb = usb_urb->context;
395 struct pcm_runtime *rt = urb->chip->pcm;
396
397 if (rt->stream_state == STREAM_STARTING) {
398 rt->stream_wait_cond = true;
399 wake_up(&rt->stream_wait_queue);
400 }
401}
402
403static int usb6fire_pcm_open(struct snd_pcm_substream *alsa_sub)
404{
405 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
406 struct pcm_substream *sub = NULL;
407 struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
408
409 if (rt->panic)
410 return -EPIPE;
411
412 mutex_lock(&rt->stream_mutex);
413 alsa_rt->hw = pcm_hw;
414
415 if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) {
416 if (rt->rate >= 0)
417 alsa_rt->hw.rates = rates_alsaid[rt->rate];
418 alsa_rt->hw.channels_max = OUT_N_CHANNELS;
419 sub = &rt->playback;
420 } else if (alsa_sub->stream == SNDRV_PCM_STREAM_CAPTURE) {
421 if (rt->rate >= 0)
422 alsa_rt->hw.rates = rates_alsaid[rt->rate];
423 alsa_rt->hw.channels_max = IN_N_CHANNELS;
424 sub = &rt->capture;
425 }
426
427 if (!sub) {
428 mutex_unlock(&rt->stream_mutex);
429 snd_printk(KERN_ERR PREFIX "invalid stream type.\n");
430 return -EINVAL;
431 }
432
433 sub->instance = alsa_sub;
434 sub->active = false;
435 mutex_unlock(&rt->stream_mutex);
436 return 0;
437}
438
439static int usb6fire_pcm_close(struct snd_pcm_substream *alsa_sub)
440{
441 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
442 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
443 unsigned long flags;
444
445 if (rt->panic)
446 return 0;
447
448 mutex_lock(&rt->stream_mutex);
449 if (sub) {
450 /* deactivate substream */
451 spin_lock_irqsave(&sub->lock, flags);
452 sub->instance = NULL;
453 sub->active = false;
454 spin_unlock_irqrestore(&sub->lock, flags);
455
456 /* all substreams closed? if so, stop streaming */
457 if (!rt->playback.instance && !rt->capture.instance) {
458 usb6fire_pcm_stream_stop(rt);
459 rt->rate = -1;
460 }
461 }
462 mutex_unlock(&rt->stream_mutex);
463 return 0;
464}
465
466static int usb6fire_pcm_hw_params(struct snd_pcm_substream *alsa_sub,
467 struct snd_pcm_hw_params *hw_params)
468{
469 return snd_pcm_lib_malloc_pages(alsa_sub,
470 params_buffer_bytes(hw_params));
471}
472
473static int usb6fire_pcm_hw_free(struct snd_pcm_substream *alsa_sub)
474{
475 return snd_pcm_lib_free_pages(alsa_sub);
476}
477
478static int usb6fire_pcm_prepare(struct snd_pcm_substream *alsa_sub)
479{
480 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
481 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
482 struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime;
483 int i;
484 int ret;
485
486 if (rt->panic)
487 return -EPIPE;
488 if (!sub)
489 return -ENODEV;
490
491 mutex_lock(&rt->stream_mutex);
492 sub->dma_off = 0;
493 sub->period_off = 0;
494
495 if (rt->stream_state == STREAM_DISABLED) {
496 for (i = 0; i < ARRAY_SIZE(rates); i++)
497 if (alsa_rt->rate == rates[i]) {
498 rt->rate = i;
499 break;
500 }
501 if (i == ARRAY_SIZE(rates)) {
502 mutex_unlock(&rt->stream_mutex);
503 snd_printk("invalid rate %d in prepare.\n",
504 alsa_rt->rate);
505 return -EINVAL;
506 }
507
508 ret = usb6fire_pcm_set_rate(rt);
509 if (ret) {
510 mutex_unlock(&rt->stream_mutex);
511 return ret;
512 }
513 ret = usb6fire_pcm_stream_start(rt);
514 if (ret) {
515 mutex_unlock(&rt->stream_mutex);
516 snd_printk(KERN_ERR PREFIX
517 "could not start pcm stream.\n");
518 return ret;
519 }
520 }
521 mutex_unlock(&rt->stream_mutex);
522 return 0;
523}
524
525static int usb6fire_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd)
526{
527 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
528 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
529 unsigned long flags;
530
531 if (rt->panic)
532 return -EPIPE;
533 if (!sub)
534 return -ENODEV;
535
536 switch (cmd) {
537 case SNDRV_PCM_TRIGGER_START:
538 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
539 spin_lock_irqsave(&sub->lock, flags);
540 sub->active = true;
541 spin_unlock_irqrestore(&sub->lock, flags);
542 return 0;
543
544 case SNDRV_PCM_TRIGGER_STOP:
545 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
546 spin_lock_irqsave(&sub->lock, flags);
547 sub->active = false;
548 spin_unlock_irqrestore(&sub->lock, flags);
549 return 0;
550
551 default:
552 return -EINVAL;
553 }
554}
555
556static snd_pcm_uframes_t usb6fire_pcm_pointer(
557 struct snd_pcm_substream *alsa_sub)
558{
559 struct pcm_substream *sub = usb6fire_pcm_get_substream(alsa_sub);
560 struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub);
561 unsigned long flags;
562 snd_pcm_uframes_t ret;
563
564 if (rt->panic || !sub)
565 return SNDRV_PCM_STATE_XRUN;
566
567 spin_lock_irqsave(&sub->lock, flags);
568 ret = sub->dma_off;
569 spin_unlock_irqrestore(&sub->lock, flags);
570 return ret;
571}
572
573static struct snd_pcm_ops pcm_ops = {
574 .open = usb6fire_pcm_open,
575 .close = usb6fire_pcm_close,
576 .ioctl = snd_pcm_lib_ioctl,
577 .hw_params = usb6fire_pcm_hw_params,
578 .hw_free = usb6fire_pcm_hw_free,
579 .prepare = usb6fire_pcm_prepare,
580 .trigger = usb6fire_pcm_trigger,
581 .pointer = usb6fire_pcm_pointer,
582};
583
584static void __devinit usb6fire_pcm_init_urb(struct pcm_urb *urb,
585 struct sfire_chip *chip, bool in, int ep,
586 void (*handler)(struct urb *))
587{
588 urb->chip = chip;
589 usb_init_urb(&urb->instance);
590 urb->instance.transfer_buffer = urb->buffer;
591 urb->instance.transfer_buffer_length =
592 PCM_N_PACKETS_PER_URB * PCM_MAX_PACKET_SIZE;
593 urb->instance.dev = chip->dev;
594 urb->instance.pipe = in ? usb_rcvisocpipe(chip->dev, ep)
595 : usb_sndisocpipe(chip->dev, ep);
596 urb->instance.interval = 1;
597 urb->instance.transfer_flags = URB_ISO_ASAP;
598 urb->instance.complete = handler;
599 urb->instance.context = urb;
600 urb->instance.number_of_packets = PCM_N_PACKETS_PER_URB;
601}
602
603int __devinit usb6fire_pcm_init(struct sfire_chip *chip)
604{
605 int i;
606 int ret;
607 struct snd_pcm *pcm;
608 struct pcm_runtime *rt =
609 kzalloc(sizeof(struct pcm_runtime), GFP_KERNEL);
610
611 if (!rt)
612 return -ENOMEM;
613
614 rt->chip = chip;
615 rt->stream_state = STREAM_DISABLED;
616 rt->rate = -1;
617 init_waitqueue_head(&rt->stream_wait_queue);
618 mutex_init(&rt->stream_mutex);
619
620 spin_lock_init(&rt->playback.lock);
621 spin_lock_init(&rt->capture.lock);
622
623 for (i = 0; i < PCM_N_URBS; i++) {
624 usb6fire_pcm_init_urb(&rt->in_urbs[i], chip, true, IN_EP,
625 usb6fire_pcm_in_urb_handler);
626 usb6fire_pcm_init_urb(&rt->out_urbs[i], chip, false, OUT_EP,
627 usb6fire_pcm_out_urb_handler);
628
629 rt->in_urbs[i].peer = &rt->out_urbs[i];
630 rt->out_urbs[i].peer = &rt->in_urbs[i];
631 }
632
633 ret = snd_pcm_new(chip->card, "DMX6FireUSB", 0, 1, 1, &pcm);
634 if (ret < 0) {
635 kfree(rt);
636 snd_printk(KERN_ERR PREFIX "cannot create pcm instance.\n");
637 return ret;
638 }
639
640 pcm->private_data = rt;
641 strcpy(pcm->name, "DMX 6Fire USB");
642 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops);
643 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_ops);
644
645 ret = snd_pcm_lib_preallocate_pages_for_all(pcm,
646 SNDRV_DMA_TYPE_CONTINUOUS,
647 snd_dma_continuous_data(GFP_KERNEL),
648 MAX_BUFSIZE, MAX_BUFSIZE);
649 if (ret) {
650 kfree(rt);
651 snd_printk(KERN_ERR PREFIX
652 "error preallocating pcm buffers.\n");
653 return ret;
654 }
655 rt->instance = pcm;
656
657 chip->pcm = rt;
658 return 0;
659}
660
661void usb6fire_pcm_abort(struct sfire_chip *chip)
662{
663 struct pcm_runtime *rt = chip->pcm;
664 int i;
665
666 if (rt) {
667 rt->panic = true;
668
669 if (rt->playback.instance)
670 snd_pcm_stop(rt->playback.instance,
671 SNDRV_PCM_STATE_XRUN);
672 if (rt->capture.instance)
673 snd_pcm_stop(rt->capture.instance,
674 SNDRV_PCM_STATE_XRUN);
675
676 for (i = 0; i < PCM_N_URBS; i++) {
677 usb_poison_urb(&rt->in_urbs[i].instance);
678 usb_poison_urb(&rt->out_urbs[i].instance);
679 }
680
681 }
682}
683
684void usb6fire_pcm_destroy(struct sfire_chip *chip)
685{
686 kfree(chip->pcm);
687 chip->pcm = NULL;
688}