linux/drivers/staging/line6/pod.c
<<
>>
Prefs
   1/*
   2 * Line6 Linux USB driver - 0.9.1beta
   3 *
   4 * Copyright (C) 2004-2010 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 <linux/slab.h>
  13#include <linux/wait.h>
  14#include <sound/control.h>
  15
  16#include "audio.h"
  17#include "capture.h"
  18#include "driver.h"
  19#include "playback.h"
  20#include "pod.h"
  21
  22#define POD_SYSEX_CODE 3
  23#define POD_BYTES_PER_FRAME 6   /* 24bit audio (stereo) */
  24
  25/* *INDENT-OFF* */
  26
  27enum {
  28        POD_SYSEX_SAVE      = 0x24,
  29        POD_SYSEX_SYSTEM    = 0x56,
  30        POD_SYSEX_SYSTEMREQ = 0x57,
  31        /* POD_SYSEX_UPDATE    = 0x6c, */  /* software update! */
  32        POD_SYSEX_STORE     = 0x71,
  33        POD_SYSEX_FINISH    = 0x72,
  34        POD_SYSEX_DUMPMEM   = 0x73,
  35        POD_SYSEX_DUMP      = 0x74,
  36        POD_SYSEX_DUMPREQ   = 0x75
  37
  38        /* dumps entire internal memory of PODxt Pro */
  39        /* POD_SYSEX_DUMPMEM2  = 0x76 */
  40};
  41
  42enum {
  43        POD_MONITOR_LEVEL  = 0x04,
  44        POD_SYSTEM_INVALID = 0x10000
  45};
  46
  47/* *INDENT-ON* */
  48
  49enum {
  50        POD_DUMP_MEMORY = 2
  51};
  52
  53enum {
  54        POD_BUSY_READ,
  55        POD_BUSY_WRITE,
  56        POD_CHANNEL_DIRTY,
  57        POD_SAVE_PRESSED,
  58        POD_BUSY_MIDISEND
  59};
  60
  61static struct snd_ratden pod_ratden = {
  62        .num_min = 78125,
  63        .num_max = 78125,
  64        .num_step = 1,
  65        .den = 2
  66};
  67
  68static struct line6_pcm_properties pod_pcm_properties = {
  69        .snd_line6_playback_hw = {
  70                                  .info = (SNDRV_PCM_INFO_MMAP |
  71                                           SNDRV_PCM_INFO_INTERLEAVED |
  72                                           SNDRV_PCM_INFO_BLOCK_TRANSFER |
  73                                           SNDRV_PCM_INFO_MMAP_VALID |
  74                                           SNDRV_PCM_INFO_PAUSE |
  75#ifdef CONFIG_PM
  76                                           SNDRV_PCM_INFO_RESUME |
  77#endif
  78                                           SNDRV_PCM_INFO_SYNC_START),
  79                                  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  80                                  .rates = SNDRV_PCM_RATE_KNOT,
  81                                  .rate_min = 39062,
  82                                  .rate_max = 39063,
  83                                  .channels_min = 2,
  84                                  .channels_max = 2,
  85                                  .buffer_bytes_max = 60000,
  86                                  .period_bytes_min = 64,
  87                                  .period_bytes_max = 8192,
  88                                  .periods_min = 1,
  89                                  .periods_max = 1024},
  90        .snd_line6_capture_hw = {
  91                                 .info = (SNDRV_PCM_INFO_MMAP |
  92                                          SNDRV_PCM_INFO_INTERLEAVED |
  93                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
  94                                          SNDRV_PCM_INFO_MMAP_VALID |
  95#ifdef CONFIG_PM
  96                                          SNDRV_PCM_INFO_RESUME |
  97#endif
  98                                          SNDRV_PCM_INFO_SYNC_START),
  99                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 100                                 .rates = SNDRV_PCM_RATE_KNOT,
 101                                 .rate_min = 39062,
 102                                 .rate_max = 39063,
 103                                 .channels_min = 2,
 104                                 .channels_max = 2,
 105                                 .buffer_bytes_max = 60000,
 106                                 .period_bytes_min = 64,
 107                                 .period_bytes_max = 8192,
 108                                 .periods_min = 1,
 109                                 .periods_max = 1024},
 110        .snd_line6_rates = {
 111                            .nrats = 1,
 112                            .rats = &pod_ratden},
 113        .bytes_per_frame = POD_BYTES_PER_FRAME
 114};
 115
 116static const char pod_version_header[] = {
 117        0xf2, 0x7e, 0x7f, 0x06, 0x02
 118};
 119
 120/* forward declarations: */
 121static void pod_startup2(unsigned long data);
 122static void pod_startup3(struct usb_line6_pod *pod);
 123
 124static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
 125                                    int size)
 126{
 127        return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
 128                                        size);
 129}
 130
 131/*
 132        Process a completely received message.
 133*/
 134void line6_pod_process_message(struct usb_line6_pod *pod)
 135{
 136        const unsigned char *buf = pod->line6.buffer_message;
 137
 138        if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
 139                pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
 140                pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
 141                                 (int) buf[10];
 142                pod_startup3(pod);
 143                return;
 144        }
 145
 146        /* Only look for sysex messages from this device */
 147        if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
 148            buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
 149                return;
 150        }
 151        if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
 152                return;
 153
 154        if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
 155                short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
 156                              ((int)buf[9] << 4) | (int)buf[10];
 157                pod->monitor_level = value;
 158        }
 159}
 160
 161/*
 162        Transmit PODxt Pro control parameter.
 163*/
 164void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
 165                                  u8 value)
 166{
 167        line6_transmit_parameter(&pod->line6, param, value);
 168}
 169
 170/*
 171        Send system parameter (from integer).
 172*/
 173static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
 174                                    int code)
 175{
 176        char *sysex;
 177        static const int size = 5;
 178
 179        sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
 180        if (!sysex)
 181                return -ENOMEM;
 182        sysex[SYSEX_DATA_OFS] = code;
 183        sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
 184        sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
 185        sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
 186        sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
 187        line6_send_sysex_message(&pod->line6, sysex, size);
 188        kfree(sysex);
 189        return 0;
 190}
 191
 192/*
 193        "read" request on "serial_number" special file.
 194*/
 195static ssize_t serial_number_show(struct device *dev,
 196                                  struct device_attribute *attr, char *buf)
 197{
 198        struct usb_interface *interface = to_usb_interface(dev);
 199        struct usb_line6_pod *pod = usb_get_intfdata(interface);
 200
 201        return sprintf(buf, "%d\n", pod->serial_number);
 202}
 203
 204/*
 205        "read" request on "firmware_version" special file.
 206*/
 207static ssize_t firmware_version_show(struct device *dev,
 208                                     struct device_attribute *attr, char *buf)
 209{
 210        struct usb_interface *interface = to_usb_interface(dev);
 211        struct usb_line6_pod *pod = usb_get_intfdata(interface);
 212
 213        return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
 214                       pod->firmware_version % 100);
 215}
 216
 217/*
 218        "read" request on "device_id" special file.
 219*/
 220static ssize_t device_id_show(struct device *dev,
 221                              struct device_attribute *attr, char *buf)
 222{
 223        struct usb_interface *interface = to_usb_interface(dev);
 224        struct usb_line6_pod *pod = usb_get_intfdata(interface);
 225
 226        return sprintf(buf, "%d\n", pod->device_id);
 227}
 228
 229/*
 230        POD startup procedure.
 231        This is a sequence of functions with special requirements (e.g., must
 232        not run immediately after initialization, must not run in interrupt
 233        context). After the last one has finished, the device is ready to use.
 234*/
 235
 236static void pod_startup1(struct usb_line6_pod *pod)
 237{
 238        CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
 239
 240        /* delay startup procedure: */
 241        line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
 242                          (unsigned long)pod);
 243}
 244
 245static void pod_startup2(unsigned long data)
 246{
 247        struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
 248        struct usb_line6 *line6 = &pod->line6;
 249
 250        CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
 251
 252        /* request firmware version: */
 253        line6_version_request_async(line6);
 254}
 255
 256static void pod_startup3(struct usb_line6_pod *pod)
 257{
 258        CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
 259
 260        /* schedule work for global work queue: */
 261        schedule_work(&pod->startup_work);
 262}
 263
 264static void pod_startup4(struct work_struct *work)
 265{
 266        struct usb_line6_pod *pod =
 267            container_of(work, struct usb_line6_pod, startup_work);
 268        struct usb_line6 *line6 = &pod->line6;
 269
 270        CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
 271
 272        /* serial number: */
 273        line6_read_serial_number(&pod->line6, &pod->serial_number);
 274
 275        /* ALSA audio interface: */
 276        line6_register_audio(line6);
 277}
 278
 279/* POD special files: */
 280static DEVICE_ATTR_RO(device_id);
 281static DEVICE_ATTR_RO(firmware_version);
 282static DEVICE_ATTR_RO(serial_number);
 283
 284/* control info callback */
 285static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
 286                                        struct snd_ctl_elem_info *uinfo)
 287{
 288        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 289        uinfo->count = 1;
 290        uinfo->value.integer.min = 0;
 291        uinfo->value.integer.max = 65535;
 292        return 0;
 293}
 294
 295/* control get callback */
 296static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
 297                                       struct snd_ctl_elem_value *ucontrol)
 298{
 299        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 300        struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
 301
 302        ucontrol->value.integer.value[0] = pod->monitor_level;
 303        return 0;
 304}
 305
 306/* control put callback */
 307static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
 308                                       struct snd_ctl_elem_value *ucontrol)
 309{
 310        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 311        struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
 312
 313        if (ucontrol->value.integer.value[0] == pod->monitor_level)
 314                return 0;
 315
 316        pod->monitor_level = ucontrol->value.integer.value[0];
 317        pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
 318                                 POD_MONITOR_LEVEL);
 319        return 1;
 320}
 321
 322/* control definition */
 323static struct snd_kcontrol_new pod_control_monitor = {
 324        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 325        .name = "Monitor Playback Volume",
 326        .index = 0,
 327        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 328        .info = snd_pod_control_monitor_info,
 329        .get = snd_pod_control_monitor_get,
 330        .put = snd_pod_control_monitor_put
 331};
 332
 333/*
 334        POD destructor.
 335*/
 336static void pod_destruct(struct usb_interface *interface)
 337{
 338        struct usb_line6_pod *pod = usb_get_intfdata(interface);
 339
 340        if (pod == NULL)
 341                return;
 342        line6_cleanup_audio(&pod->line6);
 343
 344        del_timer(&pod->startup_timer);
 345        cancel_work_sync(&pod->startup_work);
 346}
 347
 348/*
 349        Create sysfs entries.
 350*/
 351static int pod_create_files2(struct device *dev)
 352{
 353        int err;
 354
 355        CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
 356        CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
 357        CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
 358        return 0;
 359}
 360
 361/*
 362         Try to init POD device.
 363*/
 364static int pod_try_init(struct usb_interface *interface,
 365                        struct usb_line6_pod *pod)
 366{
 367        int err;
 368        struct usb_line6 *line6 = &pod->line6;
 369
 370        init_timer(&pod->startup_timer);
 371        INIT_WORK(&pod->startup_work, pod_startup4);
 372
 373        if ((interface == NULL) || (pod == NULL))
 374                return -ENODEV;
 375
 376        /* create sysfs entries: */
 377        err = pod_create_files2(&interface->dev);
 378        if (err < 0)
 379                return err;
 380
 381        /* initialize audio system: */
 382        err = line6_init_audio(line6);
 383        if (err < 0)
 384                return err;
 385
 386        /* initialize MIDI subsystem: */
 387        err = line6_init_midi(line6);
 388        if (err < 0)
 389                return err;
 390
 391        /* initialize PCM subsystem: */
 392        err = line6_init_pcm(line6, &pod_pcm_properties);
 393        if (err < 0)
 394                return err;
 395
 396        /* register monitor control: */
 397        err = snd_ctl_add(line6->card,
 398                          snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
 399        if (err < 0)
 400                return err;
 401
 402        /*
 403           When the sound card is registered at this point, the PODxt Live
 404           displays "Invalid Code Error 07", so we do it later in the event
 405           handler.
 406         */
 407
 408        if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
 409                pod->monitor_level = POD_SYSTEM_INVALID;
 410
 411                /* initiate startup procedure: */
 412                pod_startup1(pod);
 413        }
 414
 415        return 0;
 416}
 417
 418/*
 419         Init POD device (and clean up in case of failure).
 420*/
 421int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
 422{
 423        int err = pod_try_init(interface, pod);
 424
 425        if (err < 0)
 426                pod_destruct(interface);
 427
 428        return err;
 429}
 430
 431/*
 432        POD device disconnected.
 433*/
 434void line6_pod_disconnect(struct usb_interface *interface)
 435{
 436        struct usb_line6_pod *pod;
 437
 438        if (interface == NULL)
 439                return;
 440        pod = usb_get_intfdata(interface);
 441
 442        if (pod != NULL) {
 443                struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
 444                struct device *dev = &interface->dev;
 445
 446                if (line6pcm != NULL)
 447                        line6_pcm_disconnect(line6pcm);
 448
 449                if (dev != NULL) {
 450                        /* remove sysfs entries: */
 451                        device_remove_file(dev, &dev_attr_device_id);
 452                        device_remove_file(dev, &dev_attr_firmware_version);
 453                        device_remove_file(dev, &dev_attr_serial_number);
 454                }
 455        }
 456
 457        pod_destruct(interface);
 458}
 459