root/sound/usb/line6/variax.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. variax_activate_async
  2. variax_startup
  3. line6_variax_process_message
  4. line6_variax_disconnect
  5. variax_init
  6. variax_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Line 6 Linux USB driver
   4  *
   5  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
   6  */
   7 
   8 #include <linux/slab.h>
   9 #include <linux/spinlock.h>
  10 #include <linux/usb.h>
  11 #include <linux/wait.h>
  12 #include <linux/module.h>
  13 #include <sound/core.h>
  14 
  15 #include "driver.h"
  16 
  17 #define VARIAX_STARTUP_DELAY1 1000
  18 #define VARIAX_STARTUP_DELAY3 100
  19 #define VARIAX_STARTUP_DELAY4 100
  20 
  21 /*
  22         Stages of Variax startup procedure
  23 */
  24 enum {
  25         VARIAX_STARTUP_VERSIONREQ,
  26         VARIAX_STARTUP_ACTIVATE,
  27         VARIAX_STARTUP_SETUP,
  28 };
  29 
  30 enum {
  31         LINE6_PODXTLIVE_VARIAX,
  32         LINE6_VARIAX
  33 };
  34 
  35 struct usb_line6_variax {
  36         /* Generic Line 6 USB data */
  37         struct usb_line6 line6;
  38 
  39         /* Buffer for activation code */
  40         unsigned char *buffer_activate;
  41 
  42         /* Current progress in startup procedure */
  43         int startup_progress;
  44 };
  45 
  46 #define line6_to_variax(x)      container_of(x, struct usb_line6_variax, line6)
  47 
  48 #define VARIAX_OFFSET_ACTIVATE 7
  49 
  50 /*
  51         This message is sent by the device during initialization and identifies
  52         the connected guitar version.
  53 */
  54 static const char variax_init_version[] = {
  55         0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
  56         0x07, 0x00, 0x00, 0x00
  57 };
  58 
  59 /*
  60         This message is the last one sent by the device during initialization.
  61 */
  62 static const char variax_init_done[] = {
  63         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
  64 };
  65 
  66 static const char variax_activate[] = {
  67         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
  68         0xf7
  69 };
  70 
  71 static void variax_activate_async(struct usb_line6_variax *variax, int a)
  72 {
  73         variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
  74         line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
  75                                      sizeof(variax_activate));
  76 }
  77 
  78 /*
  79         Variax startup procedure.
  80         This is a sequence of functions with special requirements (e.g., must
  81         not run immediately after initialization, must not run in interrupt
  82         context). After the last one has finished, the device is ready to use.
  83 */
  84 
  85 static void variax_startup(struct usb_line6 *line6)
  86 {
  87         struct usb_line6_variax *variax = line6_to_variax(line6);
  88 
  89         switch (variax->startup_progress) {
  90         case VARIAX_STARTUP_VERSIONREQ:
  91                 /* repeat request until getting the response */
  92                 schedule_delayed_work(&line6->startup_work,
  93                                       msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
  94                 /* request firmware version: */
  95                 line6_version_request_async(line6);
  96                 break;
  97         case VARIAX_STARTUP_ACTIVATE:
  98                 /* activate device: */
  99                 variax_activate_async(variax, 1);
 100                 variax->startup_progress = VARIAX_STARTUP_SETUP;
 101                 schedule_delayed_work(&line6->startup_work,
 102                                       msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
 103                 break;
 104         case VARIAX_STARTUP_SETUP:
 105                 /* ALSA audio interface: */
 106                 snd_card_register(variax->line6.card);
 107                 break;
 108         }
 109 }
 110 
 111 /*
 112         Process a completely received message.
 113 */
 114 static void line6_variax_process_message(struct usb_line6 *line6)
 115 {
 116         struct usb_line6_variax *variax = line6_to_variax(line6);
 117         const unsigned char *buf = variax->line6.buffer_message;
 118 
 119         switch (buf[0]) {
 120         case LINE6_RESET:
 121                 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
 122                 break;
 123 
 124         case LINE6_SYSEX_BEGIN:
 125                 if (memcmp(buf + 1, variax_init_version + 1,
 126                            sizeof(variax_init_version) - 1) == 0) {
 127                         if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
 128                                 break;
 129                         variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
 130                         cancel_delayed_work(&line6->startup_work);
 131                         schedule_delayed_work(&line6->startup_work,
 132                                               msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
 133                 } else if (memcmp(buf + 1, variax_init_done + 1,
 134                                   sizeof(variax_init_done) - 1) == 0) {
 135                         /* notify of complete initialization: */
 136                         if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
 137                                 break;
 138                         cancel_delayed_work(&line6->startup_work);
 139                         schedule_delayed_work(&line6->startup_work, 0);
 140                 }
 141                 break;
 142         }
 143 }
 144 
 145 /*
 146         Variax destructor.
 147 */
 148 static void line6_variax_disconnect(struct usb_line6 *line6)
 149 {
 150         struct usb_line6_variax *variax = line6_to_variax(line6);
 151 
 152         kfree(variax->buffer_activate);
 153 }
 154 
 155 /*
 156          Try to init workbench device.
 157 */
 158 static int variax_init(struct usb_line6 *line6,
 159                        const struct usb_device_id *id)
 160 {
 161         struct usb_line6_variax *variax = line6_to_variax(line6);
 162         int err;
 163 
 164         line6->process_message = line6_variax_process_message;
 165         line6->disconnect = line6_variax_disconnect;
 166         line6->startup = variax_startup;
 167 
 168         /* initialize USB buffers: */
 169         variax->buffer_activate = kmemdup(variax_activate,
 170                                           sizeof(variax_activate), GFP_KERNEL);
 171 
 172         if (variax->buffer_activate == NULL)
 173                 return -ENOMEM;
 174 
 175         /* initialize MIDI subsystem: */
 176         err = line6_init_midi(&variax->line6);
 177         if (err < 0)
 178                 return err;
 179 
 180         /* initiate startup procedure: */
 181         schedule_delayed_work(&line6->startup_work,
 182                               msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
 183         return 0;
 184 }
 185 
 186 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
 187 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
 188 
 189 /* table of devices that work with this driver */
 190 static const struct usb_device_id variax_id_table[] = {
 191         { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
 192         { LINE6_DEVICE(0x534d),    .driver_info = LINE6_VARIAX },
 193         {}
 194 };
 195 
 196 MODULE_DEVICE_TABLE(usb, variax_id_table);
 197 
 198 static const struct line6_properties variax_properties_table[] = {
 199         [LINE6_PODXTLIVE_VARIAX] = {
 200                 .id = "PODxtLive",
 201                 .name = "PODxt Live",
 202                 .capabilities   = LINE6_CAP_CONTROL
 203                                 | LINE6_CAP_CONTROL_MIDI,
 204                 .altsetting = 1,
 205                 .ep_ctrl_r = 0x86,
 206                 .ep_ctrl_w = 0x05,
 207                 .ep_audio_r = 0x82,
 208                 .ep_audio_w = 0x01,
 209         },
 210         [LINE6_VARIAX] = {
 211                 .id = "Variax",
 212                 .name = "Variax Workbench",
 213                 .capabilities   = LINE6_CAP_CONTROL
 214                                 | LINE6_CAP_CONTROL_MIDI,
 215                 .altsetting = 1,
 216                 .ep_ctrl_r = 0x82,
 217                 .ep_ctrl_w = 0x01,
 218                 /* no audio channel */
 219         }
 220 };
 221 
 222 /*
 223         Probe USB device.
 224 */
 225 static int variax_probe(struct usb_interface *interface,
 226                         const struct usb_device_id *id)
 227 {
 228         return line6_probe(interface, id, "Line6-Variax",
 229                            &variax_properties_table[id->driver_info],
 230                            variax_init, sizeof(struct usb_line6_variax));
 231 }
 232 
 233 static struct usb_driver variax_driver = {
 234         .name = KBUILD_MODNAME,
 235         .probe = variax_probe,
 236         .disconnect = line6_disconnect,
 237 #ifdef CONFIG_PM
 238         .suspend = line6_suspend,
 239         .resume = line6_resume,
 240         .reset_resume = line6_resume,
 241 #endif
 242         .id_table = variax_id_table,
 243 };
 244 
 245 module_usb_driver(variax_driver);
 246 
 247 MODULE_DESCRIPTION("Variax Workbench USB driver");
 248 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */