linux/drivers/staging/line6/variax.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
  14#include "audio.h"
  15#include "driver.h"
  16#include "variax.h"
  17
  18#define VARIAX_OFFSET_ACTIVATE 7
  19
  20/*
  21        This message is sent by the device during initialization and identifies
  22        the connected guitar version.
  23*/
  24static const char variax_init_version[] = {
  25        0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
  26        0x07, 0x00, 0x00, 0x00
  27};
  28
  29/*
  30        This message is the last one sent by the device during initialization.
  31*/
  32static const char variax_init_done[] = {
  33        0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
  34};
  35
  36static const char variax_activate[] = {
  37        0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
  38        0xf7
  39};
  40
  41/* forward declarations: */
  42static void variax_startup2(unsigned long data);
  43static void variax_startup4(unsigned long data);
  44static void variax_startup5(unsigned long data);
  45
  46static void variax_activate_async(struct usb_line6_variax *variax, int a)
  47{
  48        variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
  49        line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
  50                                     sizeof(variax_activate));
  51}
  52
  53/*
  54        Variax startup procedure.
  55        This is a sequence of functions with special requirements (e.g., must
  56        not run immediately after initialization, must not run in interrupt
  57        context). After the last one has finished, the device is ready to use.
  58*/
  59
  60static void variax_startup1(struct usb_line6_variax *variax)
  61{
  62        CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
  63
  64        /* delay startup procedure: */
  65        line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
  66                          variax_startup2, (unsigned long)variax);
  67}
  68
  69static void variax_startup2(unsigned long data)
  70{
  71        struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
  72        struct usb_line6 *line6 = &variax->line6;
  73
  74        /* schedule another startup procedure until startup is complete: */
  75        if (variax->startup_progress >= VARIAX_STARTUP_LAST)
  76                return;
  77
  78        variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
  79        line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
  80                          variax_startup2, (unsigned long)variax);
  81
  82        /* request firmware version: */
  83        line6_version_request_async(line6);
  84}
  85
  86static void variax_startup3(struct usb_line6_variax *variax)
  87{
  88        CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
  89
  90        /* delay startup procedure: */
  91        line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
  92                          variax_startup4, (unsigned long)variax);
  93}
  94
  95static void variax_startup4(unsigned long data)
  96{
  97        struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
  98        CHECK_STARTUP_PROGRESS(variax->startup_progress,
  99                               VARIAX_STARTUP_ACTIVATE);
 100
 101        /* activate device: */
 102        variax_activate_async(variax, 1);
 103        line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
 104                          variax_startup5, (unsigned long)variax);
 105}
 106
 107static void variax_startup5(unsigned long data)
 108{
 109        struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
 110        CHECK_STARTUP_PROGRESS(variax->startup_progress,
 111                               VARIAX_STARTUP_WORKQUEUE);
 112
 113        /* schedule work for global work queue: */
 114        schedule_work(&variax->startup_work);
 115}
 116
 117static void variax_startup6(struct work_struct *work)
 118{
 119        struct usb_line6_variax *variax =
 120            container_of(work, struct usb_line6_variax, startup_work);
 121
 122        CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
 123
 124        /* ALSA audio interface: */
 125        line6_register_audio(&variax->line6);
 126}
 127
 128/*
 129        Process a completely received message.
 130*/
 131void line6_variax_process_message(struct usb_line6_variax *variax)
 132{
 133        const unsigned char *buf = variax->line6.buffer_message;
 134
 135        switch (buf[0]) {
 136        case LINE6_RESET:
 137                dev_info(variax->line6.ifcdev, "VARIAX reset\n");
 138                break;
 139
 140        case LINE6_SYSEX_BEGIN:
 141                if (memcmp(buf + 1, variax_init_version + 1,
 142                           sizeof(variax_init_version) - 1) == 0) {
 143                        variax_startup3(variax);
 144                } else if (memcmp(buf + 1, variax_init_done + 1,
 145                                  sizeof(variax_init_done) - 1) == 0) {
 146                        /* notify of complete initialization: */
 147                        variax_startup4((unsigned long)variax);
 148                }
 149                break;
 150        }
 151}
 152
 153/*
 154        Variax destructor.
 155*/
 156static void variax_destruct(struct usb_interface *interface)
 157{
 158        struct usb_line6_variax *variax = usb_get_intfdata(interface);
 159
 160        if (variax == NULL)
 161                return;
 162        line6_cleanup_audio(&variax->line6);
 163
 164        del_timer(&variax->startup_timer1);
 165        del_timer(&variax->startup_timer2);
 166        cancel_work_sync(&variax->startup_work);
 167
 168        kfree(variax->buffer_activate);
 169}
 170
 171/*
 172         Try to init workbench device.
 173*/
 174static int variax_try_init(struct usb_interface *interface,
 175                           struct usb_line6_variax *variax)
 176{
 177        int err;
 178
 179        init_timer(&variax->startup_timer1);
 180        init_timer(&variax->startup_timer2);
 181        INIT_WORK(&variax->startup_work, variax_startup6);
 182
 183        if ((interface == NULL) || (variax == NULL))
 184                return -ENODEV;
 185
 186        /* initialize USB buffers: */
 187        variax->buffer_activate = kmemdup(variax_activate,
 188                                          sizeof(variax_activate), GFP_KERNEL);
 189
 190        if (variax->buffer_activate == NULL) {
 191                dev_err(&interface->dev, "Out of memory\n");
 192                return -ENOMEM;
 193        }
 194
 195        /* initialize audio system: */
 196        err = line6_init_audio(&variax->line6);
 197        if (err < 0)
 198                return err;
 199
 200        /* initialize MIDI subsystem: */
 201        err = line6_init_midi(&variax->line6);
 202        if (err < 0)
 203                return err;
 204
 205        /* initiate startup procedure: */
 206        variax_startup1(variax);
 207        return 0;
 208}
 209
 210/*
 211         Init workbench device (and clean up in case of failure).
 212*/
 213int line6_variax_init(struct usb_interface *interface,
 214                      struct usb_line6_variax *variax)
 215{
 216        int err = variax_try_init(interface, variax);
 217
 218        if (err < 0)
 219                variax_destruct(interface);
 220
 221        return err;
 222}
 223
 224/*
 225        Workbench device disconnected.
 226*/
 227void line6_variax_disconnect(struct usb_interface *interface)
 228{
 229        if (interface == NULL)
 230                return;
 231
 232        variax_destruct(interface);
 233}
 234