blob: 9f1b085aee914cb2ee3eb266992e88bc782392a2 [file] [log] [blame]
Markus Grabner705ecec2009-02-27 19:43:04 -08001/*
Markus Grabner1027f4762010-08-12 01:35:30 +02002 * Line6 Linux USB driver - 0.9.0
Markus Grabner705ecec2009-02-27 19:43:04 -08003 *
Markus Grabner1027f4762010-08-12 01:35:30 +02004 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
Markus Grabner705ecec2009-02-27 19:43:04 -08005 *
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 Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
13
Markus Grabner705ecec2009-02-27 19:43:04 -080014#include "audio.h"
15#include "control.h"
Markus Grabner1027f4762010-08-12 01:35:30 +020016#include "driver.h"
Markus Grabner705ecec2009-02-27 19:43:04 -080017#include "variax.h"
18
19
20#define VARIAX_SYSEX_CODE 7
21#define VARIAX_SYSEX_PARAM 0x3b
22#define VARIAX_SYSEX_ACTIVATE 0x2a
23#define VARIAX_MODEL_HEADER_LENGTH 7
24#define VARIAX_MODEL_MESSAGE_LENGTH 199
25#define VARIAX_OFFSET_ACTIVATE 7
26
27
Markus Grabner1027f4762010-08-12 01:35:30 +020028/*
29 This message is sent by the device during initialization and identifies
30 the connected guitar model.
31*/
32static const char variax_init_model[] = {
33 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x69, 0x02,
34 0x00
35};
36
37/*
38 This message is sent by the device during initialization and identifies
39 the connected guitar version.
40*/
41static const char variax_init_version[] = {
42 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
43 0x07, 0x00, 0x00, 0x00
44};
45
46/*
47 This message is the last one sent by the device during initialization.
48*/
49static const char variax_init_done[] = {
50 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
51};
52
Markus Grabner705ecec2009-02-27 19:43:04 -080053static const char variax_activate[] = {
54 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
55 0xf7
56};
Markus Grabner1027f4762010-08-12 01:35:30 +020057
Markus Grabner705ecec2009-02-27 19:43:04 -080058static const char variax_request_bank[] = {
59 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7
60};
Markus Grabner1027f4762010-08-12 01:35:30 +020061
Markus Grabner705ecec2009-02-27 19:43:04 -080062static const char variax_request_model1[] = {
63 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
64 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x03,
65 0x00, 0x00, 0x00, 0xf7
66};
Markus Grabner1027f4762010-08-12 01:35:30 +020067
Markus Grabner705ecec2009-02-27 19:43:04 -080068static const char variax_request_model2[] = {
69 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
70 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03,
71 0x00, 0x00, 0x00, 0xf7
72};
73
74
Markus Grabner1027f4762010-08-12 01:35:30 +020075/* forward declarations: */
76static int variax_create_files2(struct device *dev);
77static void variax_startup2(unsigned long data);
78static void variax_startup4(unsigned long data);
79static void variax_startup5(unsigned long data);
80
81
Markus Grabner705ecec2009-02-27 19:43:04 -080082/*
83 Decode data transmitted by workbench.
84*/
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -080085static void variax_decode(const unsigned char *raw_data, unsigned char *data,
86 int raw_size)
Markus Grabner705ecec2009-02-27 19:43:04 -080087{
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -080088 for (; raw_size > 0; raw_size -= 6) {
Markus Grabner705ecec2009-02-27 19:43:04 -080089 data[2] = raw_data[0] | (raw_data[1] << 4);
90 data[1] = raw_data[2] | (raw_data[3] << 4);
91 data[0] = raw_data[4] | (raw_data[5] << 4);
92 raw_data += 6;
93 data += 3;
94 }
95}
96
Markus Grabner1027f4762010-08-12 01:35:30 +020097static void variax_activate_async(struct usb_line6_variax *variax, int a)
Markus Grabner705ecec2009-02-27 19:43:04 -080098{
Markus Grabner1027f4762010-08-12 01:35:30 +020099 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800100 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
101 sizeof(variax_activate));
Markus Grabner705ecec2009-02-27 19:43:04 -0800102}
103
104/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200105 Variax startup procedure.
106 This is a sequence of functions with special requirements (e.g., must
107 not run immediately after initialization, must not run in interrupt
108 context). After the last one has finished, the device is ready to use.
Markus Grabner705ecec2009-02-27 19:43:04 -0800109*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200110
111static void variax_startup1(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800112{
Markus Grabner1027f4762010-08-12 01:35:30 +0200113 CHECK_STARTUP_PROGRESS(variax->startup_progress, 1);
114
115 /* delay startup procedure: */
116 line6_start_timer(&variax->startup_timer, VARIAX_STARTUP_DELAY1, variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800117}
118
Markus Grabner1027f4762010-08-12 01:35:30 +0200119static void variax_startup2(unsigned long data)
Markus Grabner705ecec2009-02-27 19:43:04 -0800120{
Markus Grabner1027f4762010-08-12 01:35:30 +0200121 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
122 struct usb_line6 *line6 = &variax->line6;
123 CHECK_STARTUP_PROGRESS(variax->startup_progress, 2);
Markus Grabner705ecec2009-02-27 19:43:04 -0800124
Markus Grabner1027f4762010-08-12 01:35:30 +0200125 /* request firmware version: */
126 line6_version_request_async(line6);
127}
Markus Grabner705ecec2009-02-27 19:43:04 -0800128
Markus Grabner1027f4762010-08-12 01:35:30 +0200129static void variax_startup3(struct usb_line6_variax *variax)
130{
131 CHECK_STARTUP_PROGRESS(variax->startup_progress, 3);
132
133 /* delay startup procedure: */
134 line6_start_timer(&variax->startup_timer, VARIAX_STARTUP_DELAY3, variax_startup4, (unsigned long)variax);
135}
136
137static void variax_startup4(unsigned long data)
138{
139 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
140 CHECK_STARTUP_PROGRESS(variax->startup_progress, 4);
141
142 /* activate device: */
143 variax_activate_async(variax, 1);
144 line6_start_timer(&variax->startup_timer, VARIAX_STARTUP_DELAY4, variax_startup5, (unsigned long)variax);
145}
146
147static void variax_startup5(unsigned long data)
148{
149 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
150 CHECK_STARTUP_PROGRESS(variax->startup_progress, 5);
151
152 /* current model dump: */
153 line6_dump_request_async(&variax->dumpreq, &variax->line6, 0, VARIAX_DUMP_PASS1);
154 /* passes 2 and 3 are performed implicitly before entering variax_startup6 */
155}
156
157static void variax_startup6(struct usb_line6_variax *variax)
158{
159 CHECK_STARTUP_PROGRESS(variax->startup_progress, 6);
160
161 /* schedule work for global work queue: */
162 schedule_work(&variax->startup_work);
163}
164
165static void variax_startup7(struct work_struct *work)
166{
167 struct usb_line6_variax *variax = container_of(work, struct usb_line6_variax, startup_work);
168 struct usb_line6 *line6 = &variax->line6;
169
170 CHECK_STARTUP_PROGRESS(variax->startup_progress, 7);
171
172 /* ALSA audio interface: */
173 line6_register_audio(&variax->line6);
174
175 /* device files: */
176 line6_variax_create_files(0, 0, line6->ifcdev);
177 variax_create_files2(line6->ifcdev);
Markus Grabner705ecec2009-02-27 19:43:04 -0800178}
179
180/*
181 Process a completely received message.
182*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200183void line6_variax_process_message(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800184{
185 const unsigned char *buf = variax->line6.buffer_message;
186
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800187 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800188 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800189 switch (buf[1]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800190 case VARIAXMIDI_volume:
191 variax->volume = buf[2];
192 break;
193
194 case VARIAXMIDI_tone:
195 variax->tone = buf[2];
196 }
197
198 break;
199
200 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
201 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
202 variax->model = buf[1];
Markus Grabner1027f4762010-08-12 01:35:30 +0200203 line6_dump_request_async(&variax->dumpreq, &variax->line6, 0, VARIAX_DUMP_PASS1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800204 break;
205
206 case LINE6_RESET:
207 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800208 break;
209
210 case LINE6_SYSEX_BEGIN:
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800211 if (memcmp(buf + 1, variax_request_model1 + 1,
212 VARIAX_MODEL_HEADER_LENGTH - 1) == 0) {
213 if (variax->line6.message_length ==
214 VARIAX_MODEL_MESSAGE_LENGTH) {
215 switch (variax->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800216 case VARIAX_DUMP_PASS1:
217 variax_decode(buf + VARIAX_MODEL_HEADER_LENGTH, (unsigned char *)&variax->model_data,
218 (sizeof(variax->model_data.name) + sizeof(variax->model_data.control) / 2) * 2);
Markus Grabner1027f4762010-08-12 01:35:30 +0200219 line6_dump_request_async(&variax->dumpreq, &variax->line6, 1, VARIAX_DUMP_PASS2);
Markus Grabner705ecec2009-02-27 19:43:04 -0800220 break;
221
222 case VARIAX_DUMP_PASS2:
223 /* model name is transmitted twice, so skip it here: */
224 variax_decode(buf + VARIAX_MODEL_HEADER_LENGTH,
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800225 (unsigned char *)&variax->model_data.control + sizeof(variax->model_data.control) / 2,
226 sizeof(variax->model_data.control) / 2 * 2);
Markus Grabner1027f4762010-08-12 01:35:30 +0200227 line6_dump_request_async(&variax->dumpreq, &variax->line6, 2, VARIAX_DUMP_PASS3);
Markus Grabner705ecec2009-02-27 19:43:04 -0800228 }
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800229 } else {
Markus Grabner705ecec2009-02-27 19:43:04 -0800230 DEBUG_MESSAGES(dev_err(variax->line6.ifcdev, "illegal length %d of model data\n", variax->line6.message_length));
231 line6_dump_finished(&variax->dumpreq);
232 }
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800233 } else if (memcmp(buf + 1, variax_request_bank + 1,
Markus Grabner1027f4762010-08-12 01:35:30 +0200234 sizeof(variax_request_bank) - 2) == 0) {
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800235 memcpy(variax->bank,
236 buf + sizeof(variax_request_bank) - 1,
237 sizeof(variax->bank));
Markus Grabner705ecec2009-02-27 19:43:04 -0800238 line6_dump_finished(&variax->dumpreq);
Markus Grabner1027f4762010-08-12 01:35:30 +0200239 variax_startup6(variax);
240 } else if (memcmp(buf + 1, variax_init_model + 1,
241 sizeof(variax_init_model) - 1) == 0) {
242 memcpy(variax->guitar,
243 buf + sizeof(variax_init_model),
244 sizeof(variax->guitar));
245 } else if (memcmp(buf + 1, variax_init_version + 1,
246 sizeof(variax_init_version) - 1) == 0) {
247 variax_startup3(variax);
248 } else if (memcmp(buf + 1, variax_init_done + 1,
249 sizeof(variax_init_done) - 1) == 0) {
250 /* notify of complete initialization: */
251 variax_startup4((unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800252 }
253
254 break;
255
256 case LINE6_SYSEX_END:
257 break;
258
259 default:
260 DEBUG_MESSAGES(dev_err(variax->line6.ifcdev, "Variax: unknown message %02X\n", buf[0]));
261 }
262}
263
264/*
265 "read" request on "volume" special file.
266*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800267static ssize_t variax_get_volume(struct device *dev,
268 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800269{
270 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
271 return sprintf(buf, "%d\n", variax->volume);
272}
273
274/*
275 "write" request on "volume" special file.
276*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800277static ssize_t variax_set_volume(struct device *dev,
278 struct device_attribute *attr,
279 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800280{
281 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600282 unsigned long value;
283 int ret;
284
285 ret = strict_strtoul(buf, 10, &value);
286 if (ret)
287 return ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800288
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800289 if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_volume,
290 value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800291 variax->volume = value;
292
293 return count;
294}
295
296/*
297 "read" request on "model" special file.
298*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800299static ssize_t variax_get_model(struct device *dev,
300 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800301{
302 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
303 return sprintf(buf, "%d\n", variax->model);
304}
305
306/*
307 "write" request on "model" special file.
308*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800309static ssize_t variax_set_model(struct device *dev,
310 struct device_attribute *attr,
311 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800312{
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800313 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600314 unsigned long value;
315 int ret;
316
317 ret = strict_strtoul(buf, 10, &value);
318 if (ret)
319 return ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800320
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800321 if (line6_send_program(&variax->line6, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800322 variax->model = value;
323
324 return count;
325}
326
327/*
328 "read" request on "active" special file.
329*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800330static ssize_t variax_get_active(struct device *dev,
331 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800332{
333 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
334 return sprintf(buf, "%d\n", variax->buffer_activate[VARIAX_OFFSET_ACTIVATE]);
335}
336
337/*
338 "write" request on "active" special file.
339*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800340static ssize_t variax_set_active(struct device *dev,
341 struct device_attribute *attr,
342 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800343{
344 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600345 unsigned long value;
346 int ret;
347
348 ret = strict_strtoul(buf, 10, &value);
349 if (ret)
350 return ret;
351
Markus Grabner1027f4762010-08-12 01:35:30 +0200352 variax_activate_async(variax, value ? 1 : 0);
Markus Grabner705ecec2009-02-27 19:43:04 -0800353 return count;
354}
355
356/*
357 "read" request on "tone" special file.
358*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800359static ssize_t variax_get_tone(struct device *dev,
360 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800361{
362 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
363 return sprintf(buf, "%d\n", variax->tone);
364}
365
366/*
367 "write" request on "tone" special file.
368*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800369static ssize_t variax_set_tone(struct device *dev,
370 struct device_attribute *attr,
371 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800372{
373 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600374 unsigned long value;
375 int ret;
376
377 ret = strict_strtoul(buf, 10, &value);
378 if (ret)
379 return ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800380
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800381 if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_tone,
382 value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800383 variax->tone = value;
384
385 return count;
386}
387
388static ssize_t get_string(char *buf, const char *data, int length)
389{
390 int i;
391 memcpy(buf, data, length);
392
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800393 for (i = length; i--;) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800394 char c = buf[i];
395
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800396 if ((c != 0) && (c != ' '))
Markus Grabner705ecec2009-02-27 19:43:04 -0800397 break;
398 }
399
400 buf[i + 1] = '\n';
401 return i + 2;
402}
403
404/*
405 "read" request on "name" special file.
406*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800407static ssize_t variax_get_name(struct device *dev,
408 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800409{
410 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
Markus Grabner1027f4762010-08-12 01:35:30 +0200411 line6_dump_wait_interruptible(&variax->dumpreq);
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800412 return get_string(buf, variax->model_data.name,
413 sizeof(variax->model_data.name));
Markus Grabner705ecec2009-02-27 19:43:04 -0800414}
415
416/*
417 "read" request on "bank" special file.
418*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800419static ssize_t variax_get_bank(struct device *dev,
420 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800421{
422 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
Markus Grabner1027f4762010-08-12 01:35:30 +0200423 line6_dump_wait_interruptible(&variax->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800424 return get_string(buf, variax->bank, sizeof(variax->bank));
425}
426
427/*
428 "read" request on "dump" special file.
429*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800430static ssize_t variax_get_dump(struct device *dev,
431 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800432{
433 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
434 int retval;
Markus Grabner1027f4762010-08-12 01:35:30 +0200435 retval = line6_dump_wait_interruptible(&variax->dumpreq);
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800436 if (retval < 0)
437 return retval;
438 memcpy(buf, &variax->model_data.control,
439 sizeof(variax->model_data.control));
Markus Grabner705ecec2009-02-27 19:43:04 -0800440 return sizeof(variax->model_data.control);
441}
442
Markus Grabner1027f4762010-08-12 01:35:30 +0200443/*
444 "read" request on "guitar" special file.
445*/
446static ssize_t variax_get_guitar(struct device *dev,
447 struct device_attribute *attr, char *buf)
448{
449 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
450 return sprintf(buf, "%s\n", variax->guitar);
451}
452
453#ifdef CONFIG_LINE6_USB_RAW
454
455static char *variax_alloc_sysex_buffer(struct usb_line6_variax *variax, int code, int size)
456{
457 return line6_alloc_sysex_buffer(&variax->line6, VARIAX_SYSEX_CODE, code, size);
458}
Markus Grabner705ecec2009-02-27 19:43:04 -0800459
460/*
461 "write" request on "raw" special file.
462*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800463static ssize_t variax_set_raw2(struct device *dev,
464 struct device_attribute *attr,
465 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800466{
467 struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
468 int size;
469 int i;
470 char *sysex;
471
472 count -= count % 3;
473 size = count * 2;
474 sysex = variax_alloc_sysex_buffer(variax, VARIAX_SYSEX_PARAM, size);
475
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800476 if (!sysex)
Markus Grabner705ecec2009-02-27 19:43:04 -0800477 return 0;
478
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800479 for (i = 0; i < count; i += 3) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800480 const unsigned char *p1 = buf + i;
481 char *p2 = sysex + SYSEX_DATA_OFS + i * 2;
482 p2[0] = p1[2] & 0x0f;
483 p2[1] = p1[2] >> 4;
484 p2[2] = p1[1] & 0x0f;
485 p2[3] = p1[1] >> 4;
486 p2[4] = p1[0] & 0x0f;
487 p2[5] = p1[0] >> 4;
488 }
489
490 line6_send_sysex_message(&variax->line6, sysex, size);
491 kfree(sysex);
492 return count;
493}
494
495#endif
496
497/* Variax workbench special files: */
498static DEVICE_ATTR(model, S_IWUGO | S_IRUGO, variax_get_model, variax_set_model);
499static DEVICE_ATTR(volume, S_IWUGO | S_IRUGO, variax_get_volume, variax_set_volume);
500static DEVICE_ATTR(tone, S_IWUGO | S_IRUGO, variax_get_tone, variax_set_tone);
501static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
502static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
503static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
504static DEVICE_ATTR(active, S_IWUGO | S_IRUGO, variax_get_active, variax_set_active);
Markus Grabner1027f4762010-08-12 01:35:30 +0200505static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write);
Markus Grabner705ecec2009-02-27 19:43:04 -0800506
Markus Grabner1027f4762010-08-12 01:35:30 +0200507#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800508static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
509static DEVICE_ATTR(raw2, S_IWUGO, line6_nop_read, variax_set_raw2);
510#endif
511
512
513/*
514 Variax destructor.
515*/
516static void variax_destruct(struct usb_interface *interface)
517{
518 struct usb_line6_variax *variax = usb_get_intfdata(interface);
519 struct usb_line6 *line6;
520
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800521 if (variax == NULL)
522 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800523 line6 = &variax->line6;
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800524 if (line6 == NULL)
525 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800526 line6_cleanup_audio(line6);
527
528 /* free dump request data: */
529 line6_dumpreq_destructbuf(&variax->dumpreq, 2);
530 line6_dumpreq_destructbuf(&variax->dumpreq, 1);
531 line6_dumpreq_destruct(&variax->dumpreq);
532
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800533 kfree(variax->buffer_activate);
Markus Grabner705ecec2009-02-27 19:43:04 -0800534}
535
536/*
537 Create sysfs entries.
538*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800539static int variax_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -0800540{
541 int err;
542 CHECK_RETURN(device_create_file(dev, &dev_attr_model));
543 CHECK_RETURN(device_create_file(dev, &dev_attr_volume));
544 CHECK_RETURN(device_create_file(dev, &dev_attr_tone));
545 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
546 CHECK_RETURN(device_create_file(dev, &dev_attr_bank));
547 CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
548 CHECK_RETURN(device_create_file(dev, &dev_attr_active));
Markus Grabner1027f4762010-08-12 01:35:30 +0200549 CHECK_RETURN(device_create_file(dev, &dev_attr_guitar));
550#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800551 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
552 CHECK_RETURN(device_create_file(dev, &dev_attr_raw2));
553#endif
554 return 0;
555}
556
557/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200558 Try to init workbench device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800559*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200560static int variax_try_init(struct usb_interface *interface,
561 struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800562{
563 int err;
564
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800565 if ((interface == NULL) || (variax == NULL))
566 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800567
Markus Grabner1027f4762010-08-12 01:35:30 +0200568 init_timer(&variax->startup_timer);
569 INIT_WORK(&variax->startup_work, variax_startup7);
570
Markus Grabner705ecec2009-02-27 19:43:04 -0800571 /* initialize USB buffers: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800572 err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1,
573 sizeof(variax_request_model1));
Markus Grabner705ecec2009-02-27 19:43:04 -0800574
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800575 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800576 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800577 return err;
578 }
579
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800580 err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2,
581 sizeof(variax_request_model2), 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800582
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800583 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800584 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800585 return err;
586 }
587
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800588 err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank,
589 sizeof(variax_request_bank), 2);
Markus Grabner705ecec2009-02-27 19:43:04 -0800590
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800591 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800592 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800593 return err;
594 }
595
Julia Lawall94002c02010-05-15 23:21:43 +0200596 variax->buffer_activate = kmemdup(variax_activate,
597 sizeof(variax_activate), GFP_KERNEL);
Markus Grabner705ecec2009-02-27 19:43:04 -0800598
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800599 if (variax->buffer_activate == NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800600 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800601 return -ENOMEM;
602 }
603
Markus Grabner705ecec2009-02-27 19:43:04 -0800604 /* initialize audio system: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800605 err = line6_init_audio(&variax->line6);
606 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800607 return err;
608 }
609
610 /* initialize MIDI subsystem: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800611 err = line6_init_midi(&variax->line6);
612 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800613 return err;
614 }
615
Markus Grabner1027f4762010-08-12 01:35:30 +0200616 /* initiate startup procedure: */
617 variax_startup1(variax);
618 return 0;
619}
620
621/*
622 Init workbench device (and clean up in case of failure).
623*/
624int line6_variax_init(struct usb_interface *interface,
625 struct usb_line6_variax *variax)
626{
627 int err = variax_try_init(interface, variax);
628
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800629 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800630 variax_destruct(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800631 }
632
Markus Grabner1027f4762010-08-12 01:35:30 +0200633 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800634}
635
636/*
637 Workbench device disconnected.
638*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200639void line6_variax_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -0800640{
641 struct device *dev;
642
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800643 if (interface == NULL)
644 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800645 dev = &interface->dev;
646
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800647 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800648 /* remove sysfs entries: */
Markus Grabner1027f4762010-08-12 01:35:30 +0200649 line6_variax_remove_files(0, 0, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -0800650 device_remove_file(dev, &dev_attr_model);
651 device_remove_file(dev, &dev_attr_volume);
652 device_remove_file(dev, &dev_attr_tone);
653 device_remove_file(dev, &dev_attr_name);
654 device_remove_file(dev, &dev_attr_bank);
655 device_remove_file(dev, &dev_attr_dump);
656 device_remove_file(dev, &dev_attr_active);
Markus Grabner1027f4762010-08-12 01:35:30 +0200657 device_remove_file(dev, &dev_attr_guitar);
658#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800659 device_remove_file(dev, &dev_attr_raw);
660 device_remove_file(dev, &dev_attr_raw2);
661#endif
662 }
663
664 variax_destruct(interface);
665}