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 */ 24 static 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 */ 32 static const char variax_init_done[] = { 33 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b 34 }; 35 36 static const char variax_activate[] = { 37 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, 38 0xf7 39 }; 40 41 /* forward declarations: */ 42 static void variax_startup2(unsigned long data); 43 static void variax_startup4(unsigned long data); 44 static void variax_startup5(unsigned long data); 45 46 static 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 60 static 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 69 static 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 86 static 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 95 static void variax_startup4(unsigned long data) 96 { 97 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 98 99 CHECK_STARTUP_PROGRESS(variax->startup_progress, 100 VARIAX_STARTUP_ACTIVATE); 101 102 /* activate device: */ 103 variax_activate_async(variax, 1); 104 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, 105 variax_startup5, (unsigned long)variax); 106 } 107 108 static void variax_startup5(unsigned long data) 109 { 110 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 111 112 CHECK_STARTUP_PROGRESS(variax->startup_progress, 113 VARIAX_STARTUP_WORKQUEUE); 114 115 /* schedule work for global work queue: */ 116 schedule_work(&variax->startup_work); 117 } 118 119 static void variax_startup6(struct work_struct *work) 120 { 121 struct usb_line6_variax *variax = 122 container_of(work, struct usb_line6_variax, startup_work); 123 124 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); 125 126 /* ALSA audio interface: */ 127 line6_register_audio(&variax->line6); 128 } 129 130 /* 131 Process a completely received message. 132 */ 133 static void line6_variax_process_message(struct usb_line6 *line6) 134 { 135 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; 136 const unsigned char *buf = variax->line6.buffer_message; 137 138 switch (buf[0]) { 139 case LINE6_RESET: 140 dev_info(variax->line6.ifcdev, "VARIAX reset\n"); 141 break; 142 143 case LINE6_SYSEX_BEGIN: 144 if (memcmp(buf + 1, variax_init_version + 1, 145 sizeof(variax_init_version) - 1) == 0) { 146 variax_startup3(variax); 147 } else if (memcmp(buf + 1, variax_init_done + 1, 148 sizeof(variax_init_done) - 1) == 0) { 149 /* notify of complete initialization: */ 150 variax_startup4((unsigned long)variax); 151 } 152 break; 153 } 154 } 155 156 /* 157 Variax destructor. 158 */ 159 static void variax_destruct(struct usb_interface *interface) 160 { 161 struct usb_line6_variax *variax = usb_get_intfdata(interface); 162 163 if (variax == NULL) 164 return; 165 line6_cleanup_audio(&variax->line6); 166 167 del_timer(&variax->startup_timer1); 168 del_timer(&variax->startup_timer2); 169 cancel_work_sync(&variax->startup_work); 170 171 kfree(variax->buffer_activate); 172 } 173 174 /* 175 Workbench device disconnected. 176 */ 177 static void line6_variax_disconnect(struct usb_interface *interface) 178 { 179 if (interface == NULL) 180 return; 181 182 variax_destruct(interface); 183 } 184 185 /* 186 Try to init workbench device. 187 */ 188 static int variax_try_init(struct usb_interface *interface, 189 struct usb_line6 *line6) 190 { 191 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; 192 int err; 193 194 line6->process_message = line6_variax_process_message; 195 line6->disconnect = line6_variax_disconnect; 196 197 init_timer(&variax->startup_timer1); 198 init_timer(&variax->startup_timer2); 199 INIT_WORK(&variax->startup_work, variax_startup6); 200 201 if ((interface == NULL) || (variax == NULL)) 202 return -ENODEV; 203 204 /* initialize USB buffers: */ 205 variax->buffer_activate = kmemdup(variax_activate, 206 sizeof(variax_activate), GFP_KERNEL); 207 208 if (variax->buffer_activate == NULL) { 209 dev_err(&interface->dev, "Out of memory\n"); 210 return -ENOMEM; 211 } 212 213 /* initialize audio system: */ 214 err = line6_init_audio(&variax->line6); 215 if (err < 0) 216 return err; 217 218 /* initialize MIDI subsystem: */ 219 err = line6_init_midi(&variax->line6); 220 if (err < 0) 221 return err; 222 223 /* initiate startup procedure: */ 224 variax_startup1(variax); 225 return 0; 226 } 227 228 /* 229 Init workbench device (and clean up in case of failure). 230 */ 231 int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) 232 { 233 int err = variax_try_init(interface, line6); 234 235 if (err < 0) 236 variax_destruct(interface); 237 238 return err; 239 } 240