~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/usb/6fire/pcm.c

Version: ~ [ linux-5.6-rc3 ] ~ [ linux-5.5.6 ] ~ [ linux-5.4.22 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.106 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.171 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.214 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.214 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.82 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp