linux/drivers/staging/line6/playback.c
<<
>>
Prefs
   1/*
   2 * Line6 Linux USB driver - 0.8.0
   3 *
   4 * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License as
   8 *      published by the Free Software Foundation, version 2.
   9 *
  10 */
  11
  12#include "driver.h"
  13
  14#include <sound/core.h>
  15#include <sound/pcm.h>
  16#include <sound/pcm_params.h>
  17
  18#include "audio.h"
  19#include "pcm.h"
  20#include "pod.h"
  21#include "playback.h"
  22
  23
  24/*
  25        Software stereo volume control.
  26*/
  27static void change_volume(struct urb *urb_out, int volume[],
  28                          int bytes_per_frame)
  29{
  30        int chn = 0;
  31
  32        if (volume[0] == 256 && volume[1] == 256)
  33                return;  /* maximum volume - no change */
  34
  35        if (bytes_per_frame == 4) {
  36                short *p, *buf_end;
  37                p = (short *)urb_out->transfer_buffer;
  38                buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
  39
  40                for (; p < buf_end; ++p) {
  41                        *p = (*p * volume[chn & 1]) >> 8;
  42                        ++chn;
  43                }
  44        } else if (bytes_per_frame == 6) {
  45                unsigned char *p, *buf_end;
  46                p = (unsigned char *)urb_out->transfer_buffer;
  47                buf_end = p + urb_out->transfer_buffer_length;
  48
  49                for (; p < buf_end; p += 3) {
  50                        int val;
  51                        val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
  52                        val = (val * volume[chn & 1]) >> 8;
  53                        p[0] = val;
  54                        p[1] = val >> 8;
  55                        p[2] = val >> 16;
  56                        ++chn;
  57                }
  58        }
  59}
  60
  61/*
  62        Find a free URB, prepare audio data, and submit URB.
  63*/
  64static int submit_audio_out_urb(struct snd_pcm_substream *substream)
  65{
  66        int index;
  67        unsigned long flags;
  68        int i, urb_size, urb_frames;
  69        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
  70        const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
  71        const int frame_increment = line6pcm->properties->snd_line6_rates.rats[0].num_min;
  72        const int frame_factor = line6pcm->properties->snd_line6_rates.rats[0].den * (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
  73        struct snd_pcm_runtime *runtime = substream->runtime;
  74        struct urb *urb_out;
  75
  76        spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
  77        index = find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
  78
  79        if (index < 0 || index >= LINE6_ISO_BUFFERS) {
  80                spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
  81                dev_err(s2m(substream), "no free URB found\n");
  82                return -EINVAL;
  83        }
  84
  85        urb_out = line6pcm->urb_audio_out[index];
  86        urb_size = 0;
  87
  88        for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
  89                /* compute frame size for given sampling rate */
  90                int n, fs;
  91                struct usb_iso_packet_descriptor *fout = &urb_out->iso_frame_desc[i];
  92                line6pcm->count_out += frame_increment;
  93                n = line6pcm->count_out / frame_factor;
  94                line6pcm->count_out -= n * frame_factor;
  95                fs = n * bytes_per_frame;
  96                fout->offset = urb_size;
  97                fout->length = fs;
  98                urb_size += fs;
  99        }
 100
 101        urb_frames = urb_size / bytes_per_frame;
 102
 103        if (test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) {
 104                urb_out->transfer_buffer = line6pcm->wrap_out;
 105                memset(line6pcm->wrap_out, 0, urb_size);
 106        } else {
 107                if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
 108                        /*
 109                                The transferred area goes over buffer boundary,
 110                                copy the data to the temp buffer.
 111                        */
 112                        int len;
 113                        len = runtime->buffer_size - line6pcm->pos_out;
 114                        urb_out->transfer_buffer = line6pcm->wrap_out;
 115
 116                        if (len > 0) {
 117                                memcpy(line6pcm->wrap_out, runtime->dma_area + line6pcm->pos_out * bytes_per_frame, len * bytes_per_frame);
 118                                memcpy(line6pcm->wrap_out + len * bytes_per_frame, runtime->dma_area, (urb_frames - len) * bytes_per_frame);
 119                        } else
 120                                dev_err(s2m(substream), "driver bug: len = %d\n", len);  /* this is somewhat paranoid */
 121                } else {
 122                        /* set the buffer pointer */
 123                        urb_out->transfer_buffer = runtime->dma_area + line6pcm->pos_out * bytes_per_frame;
 124                }
 125        }
 126
 127        if ((line6pcm->pos_out += urb_frames) >= runtime->buffer_size)
 128                line6pcm->pos_out -= runtime->buffer_size;
 129
 130        urb_out->transfer_buffer_length = urb_size;
 131        urb_out->context = substream;
 132        change_volume(urb_out, line6pcm->volume, bytes_per_frame);
 133
 134#if DO_DUMP_PCM_SEND
 135        for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
 136                struct usb_iso_packet_descriptor *fout = &urb_out->iso_frame_desc[i];
 137                line6_write_hexdump(line6pcm->line6, 'P', urb_out->transfer_buffer + fout->offset, fout->length);
 138        }
 139#endif
 140
 141        if (usb_submit_urb(urb_out, GFP_ATOMIC) == 0)
 142                set_bit(index, &line6pcm->active_urb_out);
 143        else
 144                dev_err(s2m(substream), "URB out #%d submission failed\n", index);
 145
 146        spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
 147        return 0;
 148}
 149
 150/*
 151        Submit all currently available playback URBs.
 152*/
 153static int submit_audio_out_all_urbs(struct snd_pcm_substream *substream)
 154{
 155        int ret, i;
 156
 157        for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
 158                ret = submit_audio_out_urb(substream);
 159                if (ret < 0)
 160                        return ret;
 161        }
 162
 163        return 0;
 164}
 165
 166/*
 167        Unlink all currently active playback URBs.
 168*/
 169static void unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
 170{
 171        unsigned int i;
 172
 173        for (i = LINE6_ISO_BUFFERS; i--;) {
 174                if (test_bit(i, &line6pcm->active_urb_out)) {
 175                        if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
 176                                struct urb *u = line6pcm->urb_audio_out[i];
 177                                usb_unlink_urb(u);
 178                        }
 179                }
 180        }
 181}
 182
 183/*
 184        Wait until unlinking of all currently active playback URBs has been finished.
 185*/
 186static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
 187{
 188        int timeout = HZ;
 189        unsigned int i;
 190        int alive;
 191
 192        do {
 193                alive = 0;
 194                for (i = LINE6_ISO_BUFFERS; i--;) {
 195                        if (test_bit(i, &line6pcm->active_urb_out))
 196                                alive++;
 197                }
 198                if (!alive)
 199                        break;
 200                set_current_state(TASK_UNINTERRUPTIBLE);
 201                schedule_timeout(1);
 202        } while (--timeout > 0);
 203        if (alive)
 204                snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
 205
 206        line6pcm->active_urb_out = 0;
 207        line6pcm->unlink_urb_out = 0;
 208}
 209
 210/*
 211        Unlink all currently active playback URBs, and wait for finishing.
 212*/
 213void unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
 214{
 215        unlink_audio_out_urbs(line6pcm);
 216        wait_clear_audio_out_urbs(line6pcm);
 217}
 218
 219/*
 220        Callback for completed playback URB.
 221*/
 222static void audio_out_callback(struct urb *urb)
 223{
 224        int i, index, length = 0, shutdown = 0;
 225        unsigned long flags;
 226
 227        struct snd_pcm_substream *substream = (struct snd_pcm_substream *)urb->context;
 228        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 229        struct snd_pcm_runtime *runtime = substream->runtime;
 230
 231        /* find index of URB */
 232        for (index = LINE6_ISO_BUFFERS; index--;)
 233                if (urb == line6pcm->urb_audio_out[index])
 234                        break;
 235
 236        if (index < 0)
 237                return;  /* URB has been unlinked asynchronously */
 238
 239        for (i = LINE6_ISO_PACKETS; i--;)
 240                length += urb->iso_frame_desc[i].length;
 241
 242        spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
 243        line6pcm->pos_out_done += length / line6pcm->properties->bytes_per_frame;
 244
 245        if (line6pcm->pos_out_done >= runtime->buffer_size)
 246                line6pcm->pos_out_done -= runtime->buffer_size;
 247
 248        clear_bit(index, &line6pcm->active_urb_out);
 249
 250        for (i = LINE6_ISO_PACKETS; i--;)
 251                if (urb->iso_frame_desc[i].status == -ESHUTDOWN) {
 252                        shutdown = 1;
 253                        break;
 254                }
 255
 256        if (test_bit(index, &line6pcm->unlink_urb_out))
 257                shutdown = 1;
 258
 259        spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
 260
 261        if (!shutdown) {
 262                submit_audio_out_urb(substream);
 263
 264                if ((line6pcm->bytes_out += length) >= line6pcm->period_out) {
 265                        line6pcm->bytes_out -= line6pcm->period_out;
 266                        snd_pcm_period_elapsed(substream);
 267                }
 268        }
 269}
 270
 271/* open playback callback */
 272static int snd_line6_playback_open(struct snd_pcm_substream *substream)
 273{
 274        int err;
 275        struct snd_pcm_runtime *runtime = substream->runtime;
 276        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 277
 278        err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 279                                            (&line6pcm->properties->snd_line6_rates));
 280        if (err < 0)
 281                return err;
 282
 283        runtime->hw = line6pcm->properties->snd_line6_playback_hw;
 284        return 0;
 285}
 286
 287/* close playback callback */
 288static int snd_line6_playback_close(struct snd_pcm_substream *substream)
 289{
 290        return 0;
 291}
 292
 293/* hw_params playback callback */
 294static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
 295{
 296        int ret;
 297        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 298
 299        /* -- Florian Demski [FD] */
 300        /* don't ask me why, but this fixes the bug on my machine */
 301        if (line6pcm == NULL) {
 302                if (substream->pcm == NULL)
 303                        return -ENOMEM;
 304                if (substream->pcm->private_data == NULL)
 305                        return -ENOMEM;
 306                substream->private_data = substream->pcm->private_data;
 307                line6pcm = snd_pcm_substream_chip(substream);
 308        }
 309        /* -- [FD] end */
 310
 311        ret = snd_pcm_lib_malloc_pages(substream,
 312                                       params_buffer_bytes(hw_params));
 313        if (ret < 0)
 314                return ret;
 315
 316        line6pcm->period_out = params_period_bytes(hw_params);
 317        line6pcm->wrap_out = kmalloc(2 * LINE6_ISO_PACKET_SIZE_MAX, GFP_KERNEL);
 318
 319        if (!line6pcm->wrap_out) {
 320                dev_err(s2m(substream), "cannot malloc wrap_out\n");
 321                return -ENOMEM;
 322        }
 323
 324        return 0;
 325}
 326
 327/* hw_free playback callback */
 328static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
 329{
 330        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 331        unlink_wait_clear_audio_out_urbs(line6pcm);
 332
 333        kfree(line6pcm->wrap_out);
 334        line6pcm->wrap_out = NULL;
 335
 336        return snd_pcm_lib_free_pages(substream);
 337}
 338
 339/* trigger playback callback */
 340int snd_line6_playback_trigger(struct snd_pcm_substream *substream, int cmd)
 341{
 342        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 343        int err;
 344        line6pcm->count_out = 0;
 345
 346        switch (cmd) {
 347        case SNDRV_PCM_TRIGGER_START:
 348                if (!test_and_set_bit(BIT_RUNNING_PLAYBACK, &line6pcm->flags)) {
 349                        err = submit_audio_out_all_urbs(substream);
 350
 351                        if (err < 0) {
 352                                clear_bit(BIT_RUNNING_PLAYBACK, &line6pcm->flags);
 353                                return err;
 354                        }
 355                }
 356
 357                break;
 358
 359        case SNDRV_PCM_TRIGGER_STOP:
 360                if (test_and_clear_bit(BIT_RUNNING_PLAYBACK, &line6pcm->flags))
 361                        unlink_audio_out_urbs(line6pcm);
 362
 363                break;
 364
 365        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 366                set_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
 367                break;
 368
 369        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 370                clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
 371                break;
 372
 373        default:
 374                return -EINVAL;
 375        }
 376
 377        return 0;
 378}
 379
 380/* playback pointer callback */
 381static snd_pcm_uframes_t
 382snd_line6_playback_pointer(struct snd_pcm_substream *substream)
 383{
 384        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 385        return line6pcm->pos_out_done;
 386}
 387
 388/* playback operators */
 389struct snd_pcm_ops snd_line6_playback_ops = {
 390        .open =        snd_line6_playback_open,
 391        .close =       snd_line6_playback_close,
 392        .ioctl =       snd_pcm_lib_ioctl,
 393        .hw_params =   snd_line6_playback_hw_params,
 394        .hw_free =     snd_line6_playback_hw_free,
 395        .prepare =     snd_line6_prepare,
 396        .trigger =     snd_line6_trigger,
 397        .pointer =     snd_line6_playback_pointer,
 398};
 399
 400int create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
 401{
 402        int i;
 403
 404        /* create audio URBs and fill in constant values: */
 405        for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
 406                struct urb *urb;
 407
 408                /* URB for audio out: */
 409                urb = line6pcm->urb_audio_out[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
 410
 411                if (urb == NULL) {
 412                        dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
 413                        return -ENOMEM;
 414                }
 415
 416                urb->dev = line6pcm->line6->usbdev;
 417                urb->pipe = usb_sndisocpipe(line6pcm->line6->usbdev, line6pcm->ep_audio_write & USB_ENDPOINT_NUMBER_MASK);
 418                urb->transfer_flags = URB_ISO_ASAP;
 419                urb->start_frame = -1;
 420                urb->number_of_packets = LINE6_ISO_PACKETS;
 421                urb->interval = LINE6_ISO_INTERVAL;
 422                urb->error_count = 0;
 423                urb->complete = audio_out_callback;
 424        }
 425
 426        return 0;
 427}
 428