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