linux/drivers/staging/line6/pcm.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/control.h>
  16#include <sound/pcm.h>
  17#include <sound/pcm_params.h>
  18
  19#include "audio.h"
  20#include "capture.h"
  21#include "playback.h"
  22#include "pod.h"
  23
  24
  25/* trigger callback */
  26int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
  27{
  28        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
  29        struct snd_pcm_substream *s;
  30        int err;
  31        unsigned long flags;
  32
  33        spin_lock_irqsave(&line6pcm->lock_trigger, flags);
  34        clear_bit(BIT_PREPARED, &line6pcm->flags);
  35
  36        snd_pcm_group_for_each_entry(s, substream) {
  37                switch (s->stream) {
  38                case SNDRV_PCM_STREAM_PLAYBACK:
  39                        err = snd_line6_playback_trigger(s, cmd);
  40
  41                        if (err < 0) {
  42                                spin_unlock_irqrestore(&line6pcm->lock_trigger,
  43                                                       flags);
  44                                return err;
  45                        }
  46
  47                        break;
  48
  49                case SNDRV_PCM_STREAM_CAPTURE:
  50                        err = snd_line6_capture_trigger(s, cmd);
  51
  52                        if (err < 0) {
  53                                spin_unlock_irqrestore(&line6pcm->lock_trigger,
  54                                                       flags);
  55                                return err;
  56                        }
  57
  58                        break;
  59
  60                default:
  61                        dev_err(s2m(substream), "Unknown stream direction %d\n",
  62                                s->stream);
  63                }
  64        }
  65
  66        spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
  67        return 0;
  68}
  69
  70/* control info callback */
  71static int snd_line6_control_info(struct snd_kcontrol *kcontrol,
  72                                  struct snd_ctl_elem_info *uinfo)
  73{
  74        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  75        uinfo->count = 2;
  76        uinfo->value.integer.min = 0;
  77        uinfo->value.integer.max = 256;
  78        return 0;
  79}
  80
  81/* control get callback */
  82static int snd_line6_control_get(struct snd_kcontrol *kcontrol,
  83                                 struct snd_ctl_elem_value *ucontrol)
  84{
  85        int i;
  86        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
  87
  88        for (i = 2; i--;)
  89                ucontrol->value.integer.value[i] = line6pcm->volume[i];
  90
  91        return 0;
  92}
  93
  94/* control put callback */
  95static int snd_line6_control_put(struct snd_kcontrol *kcontrol,
  96                                 struct snd_ctl_elem_value *ucontrol)
  97{
  98        int i, changed = 0;
  99        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 100
 101        for (i = 2; i--;)
 102                if (line6pcm->volume[i] != ucontrol->value.integer.value[i]) {
 103                        line6pcm->volume[i] = ucontrol->value.integer.value[i];
 104                        changed = 1;
 105                }
 106
 107        return changed;
 108}
 109
 110/* control definition */
 111static struct snd_kcontrol_new line6_control = {
 112        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 113        .name = "PCM Playback Volume",
 114        .index = 0,
 115        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 116        .info = snd_line6_control_info,
 117        .get = snd_line6_control_get,
 118        .put = snd_line6_control_put
 119};
 120
 121/*
 122        Cleanup the PCM device.
 123*/
 124static void line6_cleanup_pcm(struct snd_pcm *pcm)
 125{
 126        int i;
 127        struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
 128
 129        for (i = LINE6_ISO_BUFFERS; i--;) {
 130                if (line6pcm->urb_audio_out[i]) {
 131                        usb_kill_urb(line6pcm->urb_audio_out[i]);
 132                        usb_free_urb(line6pcm->urb_audio_out[i]);
 133                }
 134                if (line6pcm->urb_audio_in[i]) {
 135                        usb_kill_urb(line6pcm->urb_audio_in[i]);
 136                        usb_free_urb(line6pcm->urb_audio_in[i]);
 137                }
 138        }
 139}
 140
 141/* create a PCM device */
 142static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
 143{
 144        struct snd_pcm *pcm;
 145        int err;
 146
 147        err = snd_pcm_new(line6pcm->line6->card,
 148                         (char *)line6pcm->line6->properties->name,
 149                         0, 1, 1, &pcm);
 150        if (err < 0)
 151                return err;
 152
 153        pcm->private_data = line6pcm;
 154        pcm->private_free = line6_cleanup_pcm;
 155        line6pcm->pcm = pcm;
 156        strcpy(pcm->name, line6pcm->line6->properties->name);
 157
 158        /* set operators */
 159        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_line6_playback_ops);
 160        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
 161
 162        /* pre-allocation of buffers */
 163        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
 164                                        snd_dma_continuous_data(GFP_KERNEL),
 165                                        64 * 1024, 128 * 1024);
 166
 167        return 0;
 168}
 169
 170/* PCM device destructor */
 171static int snd_line6_pcm_free(struct snd_device *device)
 172{
 173        return 0;
 174}
 175
 176/*
 177        Create and register the PCM device and mixer entries.
 178        Create URBs for playback and capture.
 179*/
 180int line6_init_pcm(struct usb_line6 *line6,
 181                   struct line6_pcm_properties *properties)
 182{
 183        static struct snd_device_ops pcm_ops = {
 184                .dev_free = snd_line6_pcm_free,
 185        };
 186
 187        int err;
 188        int ep_read = 0, ep_write = 0;
 189        struct snd_line6_pcm *line6pcm;
 190
 191        if (!(line6->properties->capabilities & LINE6_BIT_PCM))
 192                return 0;  /* skip PCM initialization and report success */
 193
 194        /* initialize PCM subsystem based on product id: */
 195        switch (line6->product) {
 196        case LINE6_DEVID_BASSPODXT:
 197        case LINE6_DEVID_BASSPODXTLIVE:
 198        case LINE6_DEVID_BASSPODXTPRO:
 199        case LINE6_DEVID_PODXT:
 200        case LINE6_DEVID_PODXTLIVE:
 201        case LINE6_DEVID_PODXTPRO:
 202                ep_read  = 0x82;
 203                ep_write = 0x01;
 204                break;
 205
 206        case LINE6_DEVID_PODX3:
 207        case LINE6_DEVID_PODX3LIVE:
 208                ep_read  = 0x86;
 209                ep_write = 0x02;
 210                break;
 211
 212        case LINE6_DEVID_POCKETPOD:
 213                ep_read  = 0x82;
 214                ep_write = 0x02;
 215                break;
 216
 217        case LINE6_DEVID_GUITARPORT:
 218        case LINE6_DEVID_TONEPORT_GX:
 219                ep_read  = 0x82;
 220                ep_write = 0x01;
 221                break;
 222
 223        case LINE6_DEVID_TONEPORT_UX1:
 224                ep_read  = 0x00;
 225                ep_write = 0x00;
 226                break;
 227
 228        case LINE6_DEVID_TONEPORT_UX2:
 229                ep_read  = 0x87;
 230                ep_write = 0x00;
 231                break;
 232
 233        default:
 234                MISSING_CASE;
 235        }
 236
 237        line6pcm = kzalloc(sizeof(struct snd_line6_pcm), GFP_KERNEL);
 238
 239        if (line6pcm == NULL)
 240                return -ENOMEM;
 241
 242        line6pcm->volume[0] = line6pcm->volume[1] = 128;
 243        line6pcm->line6 = line6;
 244        line6pcm->ep_audio_read = ep_read;
 245        line6pcm->ep_audio_write = ep_write;
 246        line6pcm->max_packet_size = usb_maxpacket(line6->usbdev,
 247                                                 usb_rcvintpipe(line6->usbdev,
 248                                                                ep_read),
 249                                                  0);
 250        line6pcm->properties = properties;
 251        line6->line6pcm = line6pcm;
 252
 253        /* PCM device: */
 254        err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
 255        if (err < 0)
 256                return err;
 257
 258        snd_card_set_dev(line6->card, line6->ifcdev);
 259
 260        err = snd_line6_new_pcm(line6pcm);
 261        if (err < 0)
 262                return err;
 263
 264        spin_lock_init(&line6pcm->lock_audio_out);
 265        spin_lock_init(&line6pcm->lock_audio_in);
 266        spin_lock_init(&line6pcm->lock_trigger);
 267
 268        err = create_audio_out_urbs(line6pcm);
 269        if (err < 0)
 270                return err;
 271
 272        err = create_audio_in_urbs(line6pcm);
 273        if (err < 0)
 274                return err;
 275
 276        /* mixer: */
 277        err = snd_ctl_add(line6->card, snd_ctl_new1(&line6_control, line6pcm));
 278        if (err < 0)
 279                return err;
 280
 281        return 0;
 282}
 283
 284/* prepare pcm callback */
 285int snd_line6_prepare(struct snd_pcm_substream *substream)
 286{
 287        struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 288
 289        if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
 290                unlink_wait_clear_audio_out_urbs(line6pcm);
 291                line6pcm->pos_out = 0;
 292                line6pcm->pos_out_done = 0;
 293
 294                unlink_wait_clear_audio_in_urbs(line6pcm);
 295                line6pcm->bytes_out = 0;
 296                line6pcm->pos_in_done = 0;
 297                line6pcm->bytes_in = 0;
 298        }
 299
 300        return 0;
 301}
 302