blob: 1b85eccd92b7242b9f80d79508e4fd69bbec9a8c [file] [log] [blame]
Markus Grabner705ecec2009-02-27 19:43:04 -08001/*
Markus Grabnere1a164d2010-08-23 01:08:25 +02002 * Line6 Linux USB driver - 0.9.1beta
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
Markus Grabner705ecec2009-02-27 19:43:04 -080019#define VARIAX_SYSEX_CODE 7
20#define VARIAX_SYSEX_PARAM 0x3b
21#define VARIAX_SYSEX_ACTIVATE 0x2a
22#define VARIAX_MODEL_HEADER_LENGTH 7
23#define VARIAX_MODEL_MESSAGE_LENGTH 199
24#define VARIAX_OFFSET_ACTIVATE 7
25
Markus Grabner1027f4762010-08-12 01:35:30 +020026/*
27 This message is sent by the device during initialization and identifies
28 the connected guitar model.
29*/
30static const char variax_init_model[] = {
31 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x69, 0x02,
32 0x00
33};
34
35/*
36 This message is sent by the device during initialization and identifies
37 the connected guitar version.
38*/
39static const char variax_init_version[] = {
40 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
41 0x07, 0x00, 0x00, 0x00
42};
43
44/*
45 This message is the last one sent by the device during initialization.
46*/
47static const char variax_init_done[] = {
48 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
49};
50
Markus Grabner705ecec2009-02-27 19:43:04 -080051static const char variax_activate[] = {
52 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
53 0xf7
54};
Markus Grabner1027f4762010-08-12 01:35:30 +020055
Markus Grabner705ecec2009-02-27 19:43:04 -080056static const char variax_request_bank[] = {
57 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7
58};
Markus Grabner1027f4762010-08-12 01:35:30 +020059
Markus Grabner705ecec2009-02-27 19:43:04 -080060static const char variax_request_model1[] = {
61 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
62 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x03,
63 0x00, 0x00, 0x00, 0xf7
64};
Markus Grabner1027f4762010-08-12 01:35:30 +020065
Markus Grabner705ecec2009-02-27 19:43:04 -080066static const char variax_request_model2[] = {
67 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
68 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03,
69 0x00, 0x00, 0x00, 0xf7
70};
71
Markus Grabner1027f4762010-08-12 01:35:30 +020072/* forward declarations: */
73static int variax_create_files2(struct device *dev);
74static void variax_startup2(unsigned long data);
75static void variax_startup4(unsigned long data);
76static void variax_startup5(unsigned long data);
77
Markus Grabner705ecec2009-02-27 19:43:04 -080078/*
79 Decode data transmitted by workbench.
80*/
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -080081static void variax_decode(const unsigned char *raw_data, unsigned char *data,
82 int raw_size)
Markus Grabner705ecec2009-02-27 19:43:04 -080083{
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -080084 for (; raw_size > 0; raw_size -= 6) {
Markus Grabner705ecec2009-02-27 19:43:04 -080085 data[2] = raw_data[0] | (raw_data[1] << 4);
86 data[1] = raw_data[2] | (raw_data[3] << 4);
87 data[0] = raw_data[4] | (raw_data[5] << 4);
88 raw_data += 6;
89 data += 3;
90 }
91}
92
Markus Grabner1027f4762010-08-12 01:35:30 +020093static void variax_activate_async(struct usb_line6_variax *variax, int a)
Markus Grabner705ecec2009-02-27 19:43:04 -080094{
Markus Grabner1027f4762010-08-12 01:35:30 +020095 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -080096 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
97 sizeof(variax_activate));
Markus Grabner705ecec2009-02-27 19:43:04 -080098}
99
100/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200101 Variax startup procedure.
102 This is a sequence of functions with special requirements (e.g., must
103 not run immediately after initialization, must not run in interrupt
104 context). After the last one has finished, the device is ready to use.
Markus Grabner705ecec2009-02-27 19:43:04 -0800105*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200106
107static void variax_startup1(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800108{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200109 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200110
111 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200112 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
113 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800114}
115
Markus Grabner1027f4762010-08-12 01:35:30 +0200116static void variax_startup2(unsigned long data)
Markus Grabner705ecec2009-02-27 19:43:04 -0800117{
Markus Grabner1027f4762010-08-12 01:35:30 +0200118 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
119 struct usb_line6 *line6 = &variax->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200120
121 /* schedule another startup procedure until startup is complete: */
122 if (variax->startup_progress >= VARIAX_STARTUP_LAST)
123 return;
124
125 variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
126 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
127 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800128
Markus Grabner1027f4762010-08-12 01:35:30 +0200129 /* request firmware version: */
130 line6_version_request_async(line6);
131}
Markus Grabner705ecec2009-02-27 19:43:04 -0800132
Markus Grabner1027f4762010-08-12 01:35:30 +0200133static void variax_startup3(struct usb_line6_variax *variax)
134{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200135 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200136
137 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200138 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
139 variax_startup4, (unsigned long)variax);
Markus Grabner1027f4762010-08-12 01:35:30 +0200140}
141
142static void variax_startup4(unsigned long data)
143{
144 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200145 CHECK_STARTUP_PROGRESS(variax->startup_progress,
146 VARIAX_STARTUP_ACTIVATE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200147
148 /* activate device: */
149 variax_activate_async(variax, 1);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200150 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
151 variax_startup5, (unsigned long)variax);
Markus Grabner1027f4762010-08-12 01:35:30 +0200152}
153
154static void variax_startup5(unsigned long data)
155{
156 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200157 CHECK_STARTUP_PROGRESS(variax->startup_progress,
158 VARIAX_STARTUP_DUMPREQ);
Markus Grabner1027f4762010-08-12 01:35:30 +0200159
160 /* current model dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200161 line6_dump_request_async(&variax->dumpreq, &variax->line6, 0,
162 VARIAX_DUMP_PASS1);
Stefan Hajnoczie5603cb2012-11-11 13:24:46 +0100163 /* passes 2 and 3 are performed implicitly before entering
164 * variax_startup6.
165 */
Markus Grabner1027f4762010-08-12 01:35:30 +0200166}
167
168static void variax_startup6(struct usb_line6_variax *variax)
169{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200170 CHECK_STARTUP_PROGRESS(variax->startup_progress,
171 VARIAX_STARTUP_WORKQUEUE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200172
173 /* schedule work for global work queue: */
174 schedule_work(&variax->startup_work);
175}
176
177static void variax_startup7(struct work_struct *work)
178{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200179 struct usb_line6_variax *variax =
180 container_of(work, struct usb_line6_variax, startup_work);
Markus Grabner1027f4762010-08-12 01:35:30 +0200181 struct usb_line6 *line6 = &variax->line6;
182
Markus Grabnere1a164d2010-08-23 01:08:25 +0200183 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
Markus Grabner1027f4762010-08-12 01:35:30 +0200184
185 /* ALSA audio interface: */
186 line6_register_audio(&variax->line6);
187
188 /* device files: */
189 line6_variax_create_files(0, 0, line6->ifcdev);
190 variax_create_files2(line6->ifcdev);
Markus Grabner705ecec2009-02-27 19:43:04 -0800191}
192
193/*
194 Process a completely received message.
195*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200196void line6_variax_process_message(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800197{
198 const unsigned char *buf = variax->line6.buffer_message;
199
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800200 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800201 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800202 switch (buf[1]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800203 case VARIAXMIDI_volume:
204 variax->volume = buf[2];
205 break;
206
207 case VARIAXMIDI_tone:
208 variax->tone = buf[2];
209 }
210
211 break;
212
213 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
214 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
215 variax->model = buf[1];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200216 line6_dump_request_async(&variax->dumpreq, &variax->line6, 0,
217 VARIAX_DUMP_PASS1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800218 break;
219
220 case LINE6_RESET:
221 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800222 break;
223
224 case LINE6_SYSEX_BEGIN:
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800225 if (memcmp(buf + 1, variax_request_model1 + 1,
226 VARIAX_MODEL_HEADER_LENGTH - 1) == 0) {
227 if (variax->line6.message_length ==
228 VARIAX_MODEL_MESSAGE_LENGTH) {
229 switch (variax->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800230 case VARIAX_DUMP_PASS1:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200231 variax_decode(buf +
232 VARIAX_MODEL_HEADER_LENGTH,
233 (unsigned char *)
234 &variax->model_data,
235 (sizeof
236 (variax->model_data.
237 name) +
238 sizeof(variax->
239 model_data.
240 control)
241 / 2) * 2);
242 line6_dump_request_async
243 (&variax->dumpreq, &variax->line6,
244 1, VARIAX_DUMP_PASS2);
Markus Grabner705ecec2009-02-27 19:43:04 -0800245 break;
246
247 case VARIAX_DUMP_PASS2:
248 /* model name is transmitted twice, so skip it here: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200249 variax_decode(buf +
250 VARIAX_MODEL_HEADER_LENGTH,
251 (unsigned char *)
252 &variax->
253 model_data.control +
254 sizeof(variax->model_data.
255 control)
256 / 2,
257 sizeof(variax->model_data.
258 control)
259 / 2 * 2);
260 line6_dump_request_async
261 (&variax->dumpreq, &variax->line6,
262 2, VARIAX_DUMP_PASS3);
Markus Grabner705ecec2009-02-27 19:43:04 -0800263 }
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800264 } else {
Markus Grabnere1a164d2010-08-23 01:08:25 +0200265 DEBUG_MESSAGES(dev_err
266 (variax->line6.ifcdev,
267 "illegal length %d of model data\n",
268 variax->line6.message_length));
Markus Grabner705ecec2009-02-27 19:43:04 -0800269 line6_dump_finished(&variax->dumpreq);
270 }
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800271 } else if (memcmp(buf + 1, variax_request_bank + 1,
Markus Grabner1027f4762010-08-12 01:35:30 +0200272 sizeof(variax_request_bank) - 2) == 0) {
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800273 memcpy(variax->bank,
274 buf + sizeof(variax_request_bank) - 1,
275 sizeof(variax->bank));
Markus Grabner705ecec2009-02-27 19:43:04 -0800276 line6_dump_finished(&variax->dumpreq);
Markus Grabner1027f4762010-08-12 01:35:30 +0200277 variax_startup6(variax);
278 } else if (memcmp(buf + 1, variax_init_model + 1,
279 sizeof(variax_init_model) - 1) == 0) {
280 memcpy(variax->guitar,
281 buf + sizeof(variax_init_model),
282 sizeof(variax->guitar));
283 } else if (memcmp(buf + 1, variax_init_version + 1,
284 sizeof(variax_init_version) - 1) == 0) {
285 variax_startup3(variax);
286 } else if (memcmp(buf + 1, variax_init_done + 1,
287 sizeof(variax_init_done) - 1) == 0) {
288 /* notify of complete initialization: */
289 variax_startup4((unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800290 }
291
292 break;
293
294 case LINE6_SYSEX_END:
295 break;
296
297 default:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200298 DEBUG_MESSAGES(dev_err
299 (variax->line6.ifcdev,
300 "Variax: unknown message %02X\n", buf[0]));
Markus Grabner705ecec2009-02-27 19:43:04 -0800301 }
302}
303
304/*
305 "read" request on "volume" special file.
306*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800307static ssize_t variax_get_volume(struct device *dev,
308 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800309{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200310 struct usb_line6_variax *variax =
311 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner705ecec2009-02-27 19:43:04 -0800312 return sprintf(buf, "%d\n", variax->volume);
313}
314
315/*
316 "write" request on "volume" special file.
317*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800318static ssize_t variax_set_volume(struct device *dev,
319 struct device_attribute *attr,
320 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800321{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200322 struct usb_line6_variax *variax =
323 usb_get_intfdata(to_usb_interface(dev));
Johannes Thumshirn1383ec42012-06-27 21:25:56 +0200324 u8 value;
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600325 int ret;
326
Johannes Thumshirn1383ec42012-06-27 21:25:56 +0200327 ret = kstrtou8(buf, 10, &value);
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600328 if (ret)
329 return ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800330
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800331 if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_volume,
332 value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800333 variax->volume = value;
334
335 return count;
336}
337
338/*
339 "read" request on "model" special file.
340*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800341static ssize_t variax_get_model(struct device *dev,
342 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800343{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200344 struct usb_line6_variax *variax =
345 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner705ecec2009-02-27 19:43:04 -0800346 return sprintf(buf, "%d\n", variax->model);
347}
348
349/*
350 "write" request on "model" special file.
351*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800352static ssize_t variax_set_model(struct device *dev,
353 struct device_attribute *attr,
354 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800355{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200356 struct usb_line6_variax *variax =
357 usb_get_intfdata(to_usb_interface(dev));
Johannes Thumshirn92919752012-08-14 20:22:48 +0200358 u8 value;
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600359 int ret;
360
Johannes Thumshirn92919752012-08-14 20:22:48 +0200361 ret = kstrtou8(buf, 10, &value);
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600362 if (ret)
363 return ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800364
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800365 if (line6_send_program(&variax->line6, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800366 variax->model = value;
367
368 return count;
369}
370
371/*
372 "read" request on "active" special file.
373*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800374static ssize_t variax_get_active(struct device *dev,
375 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800376{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200377 struct usb_line6_variax *variax =
378 usb_get_intfdata(to_usb_interface(dev));
379 return sprintf(buf, "%d\n",
380 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800381}
382
383/*
384 "write" request on "active" special file.
385*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800386static ssize_t variax_set_active(struct device *dev,
387 struct device_attribute *attr,
388 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800389{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200390 struct usb_line6_variax *variax =
391 usb_get_intfdata(to_usb_interface(dev));
Johannes Thumshirn92919752012-08-14 20:22:48 +0200392 u8 value;
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600393 int ret;
394
Johannes Thumshirn92919752012-08-14 20:22:48 +0200395 ret = kstrtou8(buf, 10, &value);
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600396 if (ret)
397 return ret;
398
Markus Grabner1027f4762010-08-12 01:35:30 +0200399 variax_activate_async(variax, value ? 1 : 0);
Markus Grabner705ecec2009-02-27 19:43:04 -0800400 return count;
401}
402
403/*
404 "read" request on "tone" special file.
405*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800406static ssize_t variax_get_tone(struct device *dev,
407 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800408{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200409 struct usb_line6_variax *variax =
410 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner705ecec2009-02-27 19:43:04 -0800411 return sprintf(buf, "%d\n", variax->tone);
412}
413
414/*
415 "write" request on "tone" special file.
416*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800417static ssize_t variax_set_tone(struct device *dev,
418 struct device_attribute *attr,
419 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800420{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200421 struct usb_line6_variax *variax =
422 usb_get_intfdata(to_usb_interface(dev));
Johannes Thumshirn1383ec42012-06-27 21:25:56 +0200423 u8 value;
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600424 int ret;
425
Johannes Thumshirn1383ec42012-06-27 21:25:56 +0200426 ret = kstrtou8(buf, 10, &value);
Shawn Bohrerc0e6e7c2009-11-15 22:18:00 -0600427 if (ret)
428 return ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800429
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800430 if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_tone,
431 value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800432 variax->tone = value;
433
434 return count;
435}
436
437static ssize_t get_string(char *buf, const char *data, int length)
438{
439 int i;
440 memcpy(buf, data, length);
441
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800442 for (i = length; i--;) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800443 char c = buf[i];
444
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800445 if ((c != 0) && (c != ' '))
Markus Grabner705ecec2009-02-27 19:43:04 -0800446 break;
447 }
448
449 buf[i + 1] = '\n';
450 return i + 2;
451}
452
453/*
454 "read" request on "name" special file.
455*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800456static ssize_t variax_get_name(struct device *dev,
457 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800458{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200459 struct usb_line6_variax *variax =
460 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner1027f4762010-08-12 01:35:30 +0200461 line6_dump_wait_interruptible(&variax->dumpreq);
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800462 return get_string(buf, variax->model_data.name,
463 sizeof(variax->model_data.name));
Markus Grabner705ecec2009-02-27 19:43:04 -0800464}
465
466/*
467 "read" request on "bank" special file.
468*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800469static ssize_t variax_get_bank(struct device *dev,
470 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800471{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200472 struct usb_line6_variax *variax =
473 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner1027f4762010-08-12 01:35:30 +0200474 line6_dump_wait_interruptible(&variax->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800475 return get_string(buf, variax->bank, sizeof(variax->bank));
476}
477
478/*
479 "read" request on "dump" special file.
480*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800481static ssize_t variax_get_dump(struct device *dev,
482 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800483{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200484 struct usb_line6_variax *variax =
485 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner705ecec2009-02-27 19:43:04 -0800486 int retval;
Markus Grabner1027f4762010-08-12 01:35:30 +0200487 retval = line6_dump_wait_interruptible(&variax->dumpreq);
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800488 if (retval < 0)
489 return retval;
490 memcpy(buf, &variax->model_data.control,
491 sizeof(variax->model_data.control));
Markus Grabner705ecec2009-02-27 19:43:04 -0800492 return sizeof(variax->model_data.control);
493}
494
Markus Grabner1027f4762010-08-12 01:35:30 +0200495/*
496 "read" request on "guitar" special file.
497*/
498static ssize_t variax_get_guitar(struct device *dev,
499 struct device_attribute *attr, char *buf)
500{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200501 struct usb_line6_variax *variax =
502 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner1027f4762010-08-12 01:35:30 +0200503 return sprintf(buf, "%s\n", variax->guitar);
504}
505
506#ifdef CONFIG_LINE6_USB_RAW
507
Markus Grabnere1a164d2010-08-23 01:08:25 +0200508static char *variax_alloc_sysex_buffer(struct usb_line6_variax *variax,
509 int code, int size)
Markus Grabner1027f4762010-08-12 01:35:30 +0200510{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200511 return line6_alloc_sysex_buffer(&variax->line6, VARIAX_SYSEX_CODE, code,
512 size);
Markus Grabner1027f4762010-08-12 01:35:30 +0200513}
Markus Grabner705ecec2009-02-27 19:43:04 -0800514
515/*
516 "write" request on "raw" special file.
517*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800518static ssize_t variax_set_raw2(struct device *dev,
519 struct device_attribute *attr,
520 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800521{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200522 struct usb_line6_variax *variax =
523 usb_get_intfdata(to_usb_interface(dev));
Markus Grabner705ecec2009-02-27 19:43:04 -0800524 int size;
525 int i;
526 char *sysex;
527
528 count -= count % 3;
529 size = count * 2;
530 sysex = variax_alloc_sysex_buffer(variax, VARIAX_SYSEX_PARAM, size);
531
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800532 if (!sysex)
Markus Grabner705ecec2009-02-27 19:43:04 -0800533 return 0;
534
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800535 for (i = 0; i < count; i += 3) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800536 const unsigned char *p1 = buf + i;
537 char *p2 = sysex + SYSEX_DATA_OFS + i * 2;
538 p2[0] = p1[2] & 0x0f;
539 p2[1] = p1[2] >> 4;
540 p2[2] = p1[1] & 0x0f;
541 p2[3] = p1[1] >> 4;
542 p2[4] = p1[0] & 0x0f;
543 p2[5] = p1[0] >> 4;
544 }
545
546 line6_send_sysex_message(&variax->line6, sysex, size);
547 kfree(sysex);
548 return count;
549}
550
551#endif
552
553/* Variax workbench special files: */
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800554static DEVICE_ATTR(model, S_IWUSR | S_IRUGO, variax_get_model,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200555 variax_set_model);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800556static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO, variax_get_volume,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200557 variax_set_volume);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800558static DEVICE_ATTR(tone, S_IWUSR | S_IRUGO, variax_get_tone, variax_set_tone);
Markus Grabner705ecec2009-02-27 19:43:04 -0800559static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
560static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
561static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800562static DEVICE_ATTR(active, S_IWUSR | S_IRUGO, variax_get_active,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200563 variax_set_active);
Markus Grabner1027f4762010-08-12 01:35:30 +0200564static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write);
Markus Grabner705ecec2009-02-27 19:43:04 -0800565
Markus Grabner1027f4762010-08-12 01:35:30 +0200566#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800567static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
568static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2);
Markus Grabner705ecec2009-02-27 19:43:04 -0800569#endif
570
Markus Grabner705ecec2009-02-27 19:43:04 -0800571/*
572 Variax destructor.
573*/
574static void variax_destruct(struct usb_interface *interface)
575{
576 struct usb_line6_variax *variax = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800577
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800578 if (variax == NULL)
579 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100580 line6_cleanup_audio(&variax->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800581
Markus Grabnere1a164d2010-08-23 01:08:25 +0200582 del_timer(&variax->startup_timer1);
583 del_timer(&variax->startup_timer2);
584 cancel_work_sync(&variax->startup_work);
585
Markus Grabner705ecec2009-02-27 19:43:04 -0800586 /* free dump request data: */
587 line6_dumpreq_destructbuf(&variax->dumpreq, 2);
588 line6_dumpreq_destructbuf(&variax->dumpreq, 1);
589 line6_dumpreq_destruct(&variax->dumpreq);
590
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800591 kfree(variax->buffer_activate);
Markus Grabner705ecec2009-02-27 19:43:04 -0800592}
593
594/*
595 Create sysfs entries.
596*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800597static int variax_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -0800598{
599 int err;
600 CHECK_RETURN(device_create_file(dev, &dev_attr_model));
601 CHECK_RETURN(device_create_file(dev, &dev_attr_volume));
602 CHECK_RETURN(device_create_file(dev, &dev_attr_tone));
603 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
604 CHECK_RETURN(device_create_file(dev, &dev_attr_bank));
605 CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
606 CHECK_RETURN(device_create_file(dev, &dev_attr_active));
Markus Grabner1027f4762010-08-12 01:35:30 +0200607 CHECK_RETURN(device_create_file(dev, &dev_attr_guitar));
608#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800609 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
610 CHECK_RETURN(device_create_file(dev, &dev_attr_raw2));
611#endif
612 return 0;
613}
614
615/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200616 Try to init workbench device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800617*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200618static int variax_try_init(struct usb_interface *interface,
619 struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800620{
621 int err;
622
Markus Grabnere1a164d2010-08-23 01:08:25 +0200623 init_timer(&variax->startup_timer1);
624 init_timer(&variax->startup_timer2);
625 INIT_WORK(&variax->startup_work, variax_startup7);
626
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800627 if ((interface == NULL) || (variax == NULL))
628 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800629
630 /* initialize USB buffers: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800631 err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1,
632 sizeof(variax_request_model1));
Markus Grabner705ecec2009-02-27 19:43:04 -0800633
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800634 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800635 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800636 return err;
637 }
638
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800639 err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2,
640 sizeof(variax_request_model2), 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800641
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800642 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800643 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800644 return err;
645 }
646
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800647 err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank,
648 sizeof(variax_request_bank), 2);
Markus Grabner705ecec2009-02-27 19:43:04 -0800649
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800650 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800651 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800652 return err;
653 }
654
Julia Lawall94002c02010-05-15 23:21:43 +0200655 variax->buffer_activate = kmemdup(variax_activate,
656 sizeof(variax_activate), GFP_KERNEL);
Markus Grabner705ecec2009-02-27 19:43:04 -0800657
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800658 if (variax->buffer_activate == NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800659 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800660 return -ENOMEM;
661 }
662
Markus Grabner705ecec2009-02-27 19:43:04 -0800663 /* initialize audio system: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800664 err = line6_init_audio(&variax->line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700665 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800666 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800667
668 /* initialize MIDI subsystem: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800669 err = line6_init_midi(&variax->line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700670 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800671 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800672
Markus Grabner1027f4762010-08-12 01:35:30 +0200673 /* initiate startup procedure: */
674 variax_startup1(variax);
675 return 0;
676}
677
678/*
679 Init workbench device (and clean up in case of failure).
680*/
681int line6_variax_init(struct usb_interface *interface,
682 struct usb_line6_variax *variax)
683{
684 int err = variax_try_init(interface, variax);
685
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700686 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800687 variax_destruct(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800688
Markus Grabner1027f4762010-08-12 01:35:30 +0200689 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800690}
691
692/*
693 Workbench device disconnected.
694*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200695void line6_variax_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -0800696{
697 struct device *dev;
698
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800699 if (interface == NULL)
700 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800701 dev = &interface->dev;
702
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800703 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800704 /* remove sysfs entries: */
Markus Grabner1027f4762010-08-12 01:35:30 +0200705 line6_variax_remove_files(0, 0, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -0800706 device_remove_file(dev, &dev_attr_model);
707 device_remove_file(dev, &dev_attr_volume);
708 device_remove_file(dev, &dev_attr_tone);
709 device_remove_file(dev, &dev_attr_name);
710 device_remove_file(dev, &dev_attr_bank);
711 device_remove_file(dev, &dev_attr_dump);
712 device_remove_file(dev, &dev_attr_active);
Markus Grabner1027f4762010-08-12 01:35:30 +0200713 device_remove_file(dev, &dev_attr_guitar);
714#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800715 device_remove_file(dev, &dev_attr_raw);
716 device_remove_file(dev, &dev_attr_raw2);
717#endif
718 }
719
720 variax_destruct(interface);
721}