Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 1 | /* |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 2 | * Line6 Linux USB driver - 0.9.1beta |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 3 | * |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 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 | |
Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 12 | #include <linux/slab.h> |
| 13 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 14 | #include "audio.h" |
| 15 | #include "control.h" |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 16 | #include "driver.h" |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 17 | #include "variax.h" |
| 18 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 19 | #define VARIAX_MODEL_HEADER_LENGTH 7 |
| 20 | #define VARIAX_MODEL_MESSAGE_LENGTH 199 |
| 21 | #define VARIAX_OFFSET_ACTIVATE 7 |
| 22 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 23 | /* |
| 24 | This message is sent by the device during initialization and identifies |
| 25 | the connected guitar model. |
| 26 | */ |
| 27 | static const char variax_init_model[] = { |
| 28 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x69, 0x02, |
| 29 | 0x00 |
| 30 | }; |
| 31 | |
| 32 | /* |
| 33 | This message is sent by the device during initialization and identifies |
| 34 | the connected guitar version. |
| 35 | */ |
| 36 | static const char variax_init_version[] = { |
| 37 | 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, |
| 38 | 0x07, 0x00, 0x00, 0x00 |
| 39 | }; |
| 40 | |
| 41 | /* |
| 42 | This message is the last one sent by the device during initialization. |
| 43 | */ |
| 44 | static const char variax_init_done[] = { |
| 45 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b |
| 46 | }; |
| 47 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 48 | static const char variax_activate[] = { |
| 49 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, |
| 50 | 0xf7 |
| 51 | }; |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 52 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 53 | static const char variax_request_bank[] = { |
| 54 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7 |
| 55 | }; |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 56 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 57 | static const char variax_request_model1[] = { |
| 58 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00, |
| 59 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x03, |
| 60 | 0x00, 0x00, 0x00, 0xf7 |
| 61 | }; |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 62 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 63 | static const char variax_request_model2[] = { |
| 64 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00, |
| 65 | 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03, |
| 66 | 0x00, 0x00, 0x00, 0xf7 |
| 67 | }; |
| 68 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 69 | /* forward declarations: */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 70 | static void variax_startup2(unsigned long data); |
| 71 | static void variax_startup4(unsigned long data); |
| 72 | static void variax_startup5(unsigned long data); |
| 73 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 74 | /* |
| 75 | Decode data transmitted by workbench. |
| 76 | */ |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 77 | static void variax_decode(const unsigned char *raw_data, unsigned char *data, |
| 78 | int raw_size) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 79 | { |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 80 | for (; raw_size > 0; raw_size -= 6) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 81 | data[2] = raw_data[0] | (raw_data[1] << 4); |
| 82 | data[1] = raw_data[2] | (raw_data[3] << 4); |
| 83 | data[0] = raw_data[4] | (raw_data[5] << 4); |
| 84 | raw_data += 6; |
| 85 | data += 3; |
| 86 | } |
| 87 | } |
| 88 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 89 | static void variax_activate_async(struct usb_line6_variax *variax, int a) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 90 | { |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 91 | variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 92 | line6_send_raw_message_async(&variax->line6, variax->buffer_activate, |
| 93 | sizeof(variax_activate)); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | /* |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 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. |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 101 | */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 102 | |
| 103 | static void variax_startup1(struct usb_line6_variax *variax) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 104 | { |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 105 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 106 | |
| 107 | /* delay startup procedure: */ |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 108 | line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, |
| 109 | variax_startup2, (unsigned long)variax); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 110 | } |
| 111 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 112 | static void variax_startup2(unsigned long data) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 113 | { |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 114 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; |
| 115 | struct usb_line6 *line6 = &variax->line6; |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 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); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 124 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 125 | /* request firmware version: */ |
| 126 | line6_version_request_async(line6); |
| 127 | } |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 128 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 129 | static void variax_startup3(struct usb_line6_variax *variax) |
| 130 | { |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 131 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 132 | |
| 133 | /* delay startup procedure: */ |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 134 | line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, |
| 135 | variax_startup4, (unsigned long)variax); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | static void variax_startup4(unsigned long data) |
| 139 | { |
| 140 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 141 | CHECK_STARTUP_PROGRESS(variax->startup_progress, |
| 142 | VARIAX_STARTUP_ACTIVATE); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 143 | |
| 144 | /* activate device: */ |
| 145 | variax_activate_async(variax, 1); |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 146 | line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, |
| 147 | variax_startup5, (unsigned long)variax); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 148 | } |
| 149 | |
| 150 | static void variax_startup5(unsigned long data) |
| 151 | { |
| 152 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 153 | CHECK_STARTUP_PROGRESS(variax->startup_progress, |
| 154 | VARIAX_STARTUP_DUMPREQ); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 155 | |
| 156 | /* current model dump: */ |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 157 | line6_dump_request_async(&variax->dumpreq, &variax->line6, 0, |
| 158 | VARIAX_DUMP_PASS1); |
Stefan Hajnoczi | e5603cb | 2012-11-11 13:24:46 +0100 | [diff] [blame] | 159 | /* passes 2 and 3 are performed implicitly before entering |
| 160 | * variax_startup6. |
| 161 | */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | static void variax_startup6(struct usb_line6_variax *variax) |
| 165 | { |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 166 | CHECK_STARTUP_PROGRESS(variax->startup_progress, |
| 167 | VARIAX_STARTUP_WORKQUEUE); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 168 | |
| 169 | /* schedule work for global work queue: */ |
| 170 | schedule_work(&variax->startup_work); |
| 171 | } |
| 172 | |
| 173 | static void variax_startup7(struct work_struct *work) |
| 174 | { |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 175 | struct usb_line6_variax *variax = |
| 176 | container_of(work, struct usb_line6_variax, startup_work); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 177 | struct usb_line6 *line6 = &variax->line6; |
| 178 | |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 179 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 180 | |
| 181 | /* ALSA audio interface: */ |
| 182 | line6_register_audio(&variax->line6); |
| 183 | |
| 184 | /* device files: */ |
| 185 | line6_variax_create_files(0, 0, line6->ifcdev); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | /* |
| 189 | Process a completely received message. |
| 190 | */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 191 | void line6_variax_process_message(struct usb_line6_variax *variax) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 192 | { |
| 193 | const unsigned char *buf = variax->line6.buffer_message; |
| 194 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 195 | switch (buf[0]) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 196 | case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST: |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 197 | break; |
| 198 | |
| 199 | case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE: |
| 200 | case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST: |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 201 | line6_dump_request_async(&variax->dumpreq, &variax->line6, 0, |
| 202 | VARIAX_DUMP_PASS1); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 203 | break; |
| 204 | |
| 205 | case LINE6_RESET: |
| 206 | dev_info(variax->line6.ifcdev, "VARIAX reset\n"); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 207 | break; |
| 208 | |
| 209 | case LINE6_SYSEX_BEGIN: |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 210 | if (memcmp(buf + 1, variax_request_model1 + 1, |
| 211 | VARIAX_MODEL_HEADER_LENGTH - 1) == 0) { |
| 212 | if (variax->line6.message_length == |
| 213 | VARIAX_MODEL_MESSAGE_LENGTH) { |
| 214 | switch (variax->dumpreq.in_progress) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 215 | case VARIAX_DUMP_PASS1: |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 216 | line6_dump_request_async |
| 217 | (&variax->dumpreq, &variax->line6, |
| 218 | 1, VARIAX_DUMP_PASS2); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 219 | break; |
| 220 | |
| 221 | case VARIAX_DUMP_PASS2: |
| 222 | /* model name is transmitted twice, so skip it here: */ |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 223 | variax_decode(buf + |
| 224 | VARIAX_MODEL_HEADER_LENGTH, |
| 225 | (unsigned char *) |
| 226 | &variax-> |
| 227 | model_data.control + |
| 228 | sizeof(variax->model_data. |
| 229 | control) |
| 230 | / 2, |
| 231 | sizeof(variax->model_data. |
| 232 | control) |
| 233 | / 2 * 2); |
| 234 | line6_dump_request_async |
| 235 | (&variax->dumpreq, &variax->line6, |
| 236 | 2, VARIAX_DUMP_PASS3); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 237 | } |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 238 | } else { |
Stefan Hajnoczi | e00d33c | 2012-11-11 13:52:24 +0100 | [diff] [blame] | 239 | dev_dbg(variax->line6.ifcdev, |
| 240 | "illegal length %d of model data\n", |
| 241 | variax->line6.message_length); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 242 | line6_dump_finished(&variax->dumpreq); |
| 243 | } |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 244 | } else if (memcmp(buf + 1, variax_request_bank + 1, |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 245 | sizeof(variax_request_bank) - 2) == 0) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 246 | line6_dump_finished(&variax->dumpreq); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 247 | variax_startup6(variax); |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 248 | } else if (memcmp(buf + 1, variax_init_version + 1, |
| 249 | sizeof(variax_init_version) - 1) == 0) { |
| 250 | variax_startup3(variax); |
| 251 | } else if (memcmp(buf + 1, variax_init_done + 1, |
| 252 | sizeof(variax_init_done) - 1) == 0) { |
| 253 | /* notify of complete initialization: */ |
| 254 | variax_startup4((unsigned long)variax); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 255 | } |
| 256 | |
| 257 | break; |
| 258 | |
| 259 | case LINE6_SYSEX_END: |
| 260 | break; |
| 261 | |
| 262 | default: |
Stefan Hajnoczi | e00d33c | 2012-11-11 13:52:24 +0100 | [diff] [blame] | 263 | dev_dbg(variax->line6.ifcdev, |
| 264 | "Variax: unknown message %02X\n", buf[0]); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 265 | } |
| 266 | } |
| 267 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 268 | /* |
| 269 | Variax destructor. |
| 270 | */ |
| 271 | static void variax_destruct(struct usb_interface *interface) |
| 272 | { |
| 273 | struct usb_line6_variax *variax = usb_get_intfdata(interface); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 274 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 275 | if (variax == NULL) |
| 276 | return; |
Stefan Hajnoczi | 188e664 | 2011-12-10 02:12:30 +0100 | [diff] [blame] | 277 | line6_cleanup_audio(&variax->line6); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 278 | |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 279 | del_timer(&variax->startup_timer1); |
| 280 | del_timer(&variax->startup_timer2); |
| 281 | cancel_work_sync(&variax->startup_work); |
| 282 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 283 | /* free dump request data: */ |
| 284 | line6_dumpreq_destructbuf(&variax->dumpreq, 2); |
| 285 | line6_dumpreq_destructbuf(&variax->dumpreq, 1); |
| 286 | line6_dumpreq_destruct(&variax->dumpreq); |
| 287 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 288 | kfree(variax->buffer_activate); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 289 | } |
| 290 | |
| 291 | /* |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 292 | Try to init workbench device. |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 293 | */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 294 | static int variax_try_init(struct usb_interface *interface, |
| 295 | struct usb_line6_variax *variax) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 296 | { |
| 297 | int err; |
| 298 | |
Markus Grabner | e1a164d | 2010-08-23 01:08:25 +0200 | [diff] [blame] | 299 | init_timer(&variax->startup_timer1); |
| 300 | init_timer(&variax->startup_timer2); |
| 301 | INIT_WORK(&variax->startup_work, variax_startup7); |
| 302 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 303 | if ((interface == NULL) || (variax == NULL)) |
| 304 | return -ENODEV; |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 305 | |
| 306 | /* initialize USB buffers: */ |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 307 | err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1, |
| 308 | sizeof(variax_request_model1)); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 309 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 310 | if (err < 0) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 311 | dev_err(&interface->dev, "Out of memory\n"); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 312 | return err; |
| 313 | } |
| 314 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 315 | err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2, |
| 316 | sizeof(variax_request_model2), 1); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 317 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 318 | if (err < 0) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 319 | dev_err(&interface->dev, "Out of memory\n"); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 320 | return err; |
| 321 | } |
| 322 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 323 | err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank, |
| 324 | sizeof(variax_request_bank), 2); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 325 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 326 | if (err < 0) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 327 | dev_err(&interface->dev, "Out of memory\n"); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 328 | return err; |
| 329 | } |
| 330 | |
Julia Lawall | 94002c0 | 2010-05-15 23:21:43 +0200 | [diff] [blame] | 331 | variax->buffer_activate = kmemdup(variax_activate, |
| 332 | sizeof(variax_activate), GFP_KERNEL); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 333 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 334 | if (variax->buffer_activate == NULL) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 335 | dev_err(&interface->dev, "Out of memory\n"); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 336 | return -ENOMEM; |
| 337 | } |
| 338 | |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 339 | /* initialize audio system: */ |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 340 | err = line6_init_audio(&variax->line6); |
Greg Kroah-Hartman | 027360c | 2010-09-21 16:58:00 -0700 | [diff] [blame] | 341 | if (err < 0) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 342 | return err; |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 343 | |
| 344 | /* initialize MIDI subsystem: */ |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 345 | err = line6_init_midi(&variax->line6); |
Greg Kroah-Hartman | 027360c | 2010-09-21 16:58:00 -0700 | [diff] [blame] | 346 | if (err < 0) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 347 | return err; |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 348 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 349 | /* initiate startup procedure: */ |
| 350 | variax_startup1(variax); |
| 351 | return 0; |
| 352 | } |
| 353 | |
| 354 | /* |
| 355 | Init workbench device (and clean up in case of failure). |
| 356 | */ |
| 357 | int line6_variax_init(struct usb_interface *interface, |
| 358 | struct usb_line6_variax *variax) |
| 359 | { |
| 360 | int err = variax_try_init(interface, variax); |
| 361 | |
Greg Kroah-Hartman | 027360c | 2010-09-21 16:58:00 -0700 | [diff] [blame] | 362 | if (err < 0) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 363 | variax_destruct(interface); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 364 | |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 365 | return err; |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 366 | } |
| 367 | |
| 368 | /* |
| 369 | Workbench device disconnected. |
| 370 | */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 371 | void line6_variax_disconnect(struct usb_interface *interface) |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 372 | { |
| 373 | struct device *dev; |
| 374 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 375 | if (interface == NULL) |
| 376 | return; |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 377 | dev = &interface->dev; |
| 378 | |
Greg Kroah-Hartman | 9cd57f7 | 2009-02-27 22:43:57 -0800 | [diff] [blame] | 379 | if (dev != NULL) { |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 380 | /* remove sysfs entries: */ |
Markus Grabner | 1027f476 | 2010-08-12 01:35:30 +0200 | [diff] [blame] | 381 | line6_variax_remove_files(0, 0, dev); |
Markus Grabner | 705ecec | 2009-02-27 19:43:04 -0800 | [diff] [blame] | 382 | } |
| 383 | |
| 384 | variax_destruct(interface); |
| 385 | } |