1 /* 2 * Line 6 Linux USB driver 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/spinlock.h> 14 #include <linux/usb.h> 15 #include <linux/wait.h> 16 #include <linux/module.h> 17 #include <sound/core.h> 18 19 #include "driver.h" 20 21 #define VARIAX_STARTUP_DELAY1 1000 22 #define VARIAX_STARTUP_DELAY3 100 23 #define VARIAX_STARTUP_DELAY4 100 24 25 /* 26 Stages of Variax startup procedure 27 */ 28 enum { 29 VARIAX_STARTUP_INIT = 1, 30 VARIAX_STARTUP_VERSIONREQ, 31 VARIAX_STARTUP_WAIT, 32 VARIAX_STARTUP_ACTIVATE, 33 VARIAX_STARTUP_WORKQUEUE, 34 VARIAX_STARTUP_SETUP, 35 VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 36 }; 37 38 enum { 39 LINE6_PODXTLIVE_VARIAX, 40 LINE6_VARIAX 41 }; 42 43 struct usb_line6_variax { 44 /* Generic Line 6 USB data */ 45 struct usb_line6 line6; 46 47 /* Buffer for activation code */ 48 unsigned char *buffer_activate; 49 50 /* Handler for device initialization */ 51 struct work_struct startup_work; 52 53 /* Timers for device initialization */ 54 struct timer_list startup_timer1; 55 struct timer_list startup_timer2; 56 57 /* Current progress in startup procedure */ 58 int startup_progress; 59 }; 60 61 #define VARIAX_OFFSET_ACTIVATE 7 62 63 /* 64 This message is sent by the device during initialization and identifies 65 the connected guitar version. 66 */ 67 static const char variax_init_version[] = { 68 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, 69 0x07, 0x00, 0x00, 0x00 70 }; 71 72 /* 73 This message is the last one sent by the device during initialization. 74 */ 75 static const char variax_init_done[] = { 76 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b 77 }; 78 79 static const char variax_activate[] = { 80 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, 81 0xf7 82 }; 83 84 /* forward declarations: */ 85 static void variax_startup2(unsigned long data); 86 static void variax_startup4(unsigned long data); 87 static void variax_startup5(unsigned long data); 88 89 static void variax_activate_async(struct usb_line6_variax *variax, int a) 90 { 91 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; 92 line6_send_raw_message_async(&variax->line6, variax->buffer_activate, 93 sizeof(variax_activate)); 94 } 95 96 /* 97 Variax startup procedure. 98 This is a sequence of functions with special requirements (e.g., must 99 not run immediately after initialization, must not run in interrupt 100 context). After the last one has finished, the device is ready to use. 101 */ 102 103 static void variax_startup1(struct usb_line6_variax *variax) 104 { 105 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); 106 107 /* delay startup procedure: */ 108 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, 109 variax_startup2, (unsigned long)variax); 110 } 111 112 static void variax_startup2(unsigned long data) 113 { 114 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 115 struct usb_line6 *line6 = &variax->line6; 116 117 /* schedule another startup procedure until startup is complete: */ 118 if (variax->startup_progress >= VARIAX_STARTUP_LAST) 119 return; 120 121 variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; 122 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, 123 variax_startup2, (unsigned long)variax); 124 125 /* request firmware version: */ 126 line6_version_request_async(line6); 127 } 128 129 static void variax_startup3(struct usb_line6_variax *variax) 130 { 131 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); 132 133 /* delay startup procedure: */ 134 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, 135 variax_startup4, (unsigned long)variax); 136 } 137 138 static void variax_startup4(unsigned long data) 139 { 140 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 141 142 CHECK_STARTUP_PROGRESS(variax->startup_progress, 143 VARIAX_STARTUP_ACTIVATE); 144 145 /* activate device: */ 146 variax_activate_async(variax, 1); 147 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, 148 variax_startup5, (unsigned long)variax); 149 } 150 151 static void variax_startup5(unsigned long data) 152 { 153 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 154 155 CHECK_STARTUP_PROGRESS(variax->startup_progress, 156 VARIAX_STARTUP_WORKQUEUE); 157 158 /* schedule work for global work queue: */ 159 schedule_work(&variax->startup_work); 160 } 161 162 static void variax_startup6(struct work_struct *work) 163 { 164 struct usb_line6_variax *variax = 165 container_of(work, struct usb_line6_variax, startup_work); 166 167 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); 168 169 /* ALSA audio interface: */ 170 snd_card_register(variax->line6.card); 171 } 172 173 /* 174 Process a completely received message. 175 */ 176 static void line6_variax_process_message(struct usb_line6 *line6) 177 { 178 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; 179 const unsigned char *buf = variax->line6.buffer_message; 180 181 switch (buf[0]) { 182 case LINE6_RESET: 183 dev_info(variax->line6.ifcdev, "VARIAX reset\n"); 184 break; 185 186 case LINE6_SYSEX_BEGIN: 187 if (memcmp(buf + 1, variax_init_version + 1, 188 sizeof(variax_init_version) - 1) == 0) { 189 variax_startup3(variax); 190 } else if (memcmp(buf + 1, variax_init_done + 1, 191 sizeof(variax_init_done) - 1) == 0) { 192 /* notify of complete initialization: */ 193 variax_startup4((unsigned long)variax); 194 } 195 break; 196 } 197 } 198 199 /* 200 Variax destructor. 201 */ 202 static void line6_variax_disconnect(struct usb_line6 *line6) 203 { 204 struct usb_line6_variax *variax = (struct usb_line6_variax *)line6; 205 206 del_timer(&variax->startup_timer1); 207 del_timer(&variax->startup_timer2); 208 cancel_work_sync(&variax->startup_work); 209 210 kfree(variax->buffer_activate); 211 } 212 213 /* 214 Try to init workbench device. 215 */ 216 static int variax_init(struct usb_line6 *line6, 217 const struct usb_device_id *id) 218 { 219 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; 220 int err; 221 222 line6->process_message = line6_variax_process_message; 223 line6->disconnect = line6_variax_disconnect; 224 225 init_timer(&variax->startup_timer1); 226 init_timer(&variax->startup_timer2); 227 INIT_WORK(&variax->startup_work, variax_startup6); 228 229 /* initialize USB buffers: */ 230 variax->buffer_activate = kmemdup(variax_activate, 231 sizeof(variax_activate), GFP_KERNEL); 232 233 if (variax->buffer_activate == NULL) 234 return -ENOMEM; 235 236 /* initialize MIDI subsystem: */ 237 err = line6_init_midi(&variax->line6); 238 if (err < 0) 239 return err; 240 241 /* initiate startup procedure: */ 242 variax_startup1(variax); 243 return 0; 244 } 245 246 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) 247 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) 248 249 /* table of devices that work with this driver */ 250 static const struct usb_device_id variax_id_table[] = { 251 { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, 252 { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, 253 {} 254 }; 255 256 MODULE_DEVICE_TABLE(usb, variax_id_table); 257 258 static const struct line6_properties variax_properties_table[] = { 259 [LINE6_PODXTLIVE_VARIAX] = { 260 .id = "PODxtLive", 261 .name = "PODxt Live", 262 .capabilities = LINE6_CAP_CONTROL 263 | LINE6_CAP_CONTROL_MIDI, 264 .altsetting = 1, 265 .ep_ctrl_r = 0x86, 266 .ep_ctrl_w = 0x05, 267 .ep_audio_r = 0x82, 268 .ep_audio_w = 0x01, 269 }, 270 [LINE6_VARIAX] = { 271 .id = "Variax", 272 .name = "Variax Workbench", 273 .capabilities = LINE6_CAP_CONTROL 274 | LINE6_CAP_CONTROL_MIDI, 275 .altsetting = 1, 276 .ep_ctrl_r = 0x82, 277 .ep_ctrl_w = 0x01, 278 /* no audio channel */ 279 } 280 }; 281 282 /* 283 Probe USB device. 284 */ 285 static int variax_probe(struct usb_interface *interface, 286 const struct usb_device_id *id) 287 { 288 return line6_probe(interface, id, "Line6-Variax", 289 &variax_properties_table[id->driver_info], 290 variax_init, sizeof(struct usb_line6_variax)); 291 } 292 293 static struct usb_driver variax_driver = { 294 .name = KBUILD_MODNAME, 295 .probe = variax_probe, 296 .disconnect = line6_disconnect, 297 #ifdef CONFIG_PM 298 .suspend = line6_suspend, 299 .resume = line6_resume, 300 .reset_resume = line6_resume, 301 #endif 302 .id_table = variax_id_table, 303 }; 304 305 module_usb_driver(variax_driver); 306 307 MODULE_DESCRIPTION("Vairax Workbench USB driver"); 308 MODULE_LICENSE("GPL"); 309