Root/drivers/staging/line6/variax.c

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 "control.h"
16#include "driver.h"
17#include "variax.h"
18
19#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
26/*
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
51static const char variax_activate[] = {
52    0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
53    0xf7
54};
55
56static const char variax_request_bank[] = {
57    0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7
58};
59
60static 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};
65
66static 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
72/* 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
78/*
79    Decode data transmitted by workbench.
80*/
81static void variax_decode(const unsigned char *raw_data, unsigned char *data,
82              int raw_size)
83{
84    for (; raw_size > 0; raw_size -= 6) {
85        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
93static void variax_activate_async(struct usb_line6_variax *variax, int a)
94{
95    variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
96    line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
97                     sizeof(variax_activate));
98}
99
100/*
101    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.
105*/
106
107static void variax_startup1(struct usb_line6_variax *variax)
108{
109    CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
110
111    /* delay startup procedure: */
112    line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
113              variax_startup2, (unsigned long)variax);
114}
115
116static void variax_startup2(unsigned long data)
117{
118    struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
119    struct usb_line6 *line6 = &variax->line6;
120
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);
128
129    /* request firmware version: */
130    line6_version_request_async(line6);
131}
132
133static void variax_startup3(struct usb_line6_variax *variax)
134{
135    CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
136
137    /* delay startup procedure: */
138    line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
139              variax_startup4, (unsigned long)variax);
140}
141
142static void variax_startup4(unsigned long data)
143{
144    struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
145    CHECK_STARTUP_PROGRESS(variax->startup_progress,
146                   VARIAX_STARTUP_ACTIVATE);
147
148    /* activate device: */
149    variax_activate_async(variax, 1);
150    line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
151              variax_startup5, (unsigned long)variax);
152}
153
154static void variax_startup5(unsigned long data)
155{
156    struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
157    CHECK_STARTUP_PROGRESS(variax->startup_progress,
158                   VARIAX_STARTUP_DUMPREQ);
159
160    /* current model dump: */
161    line6_dump_request_async(&variax->dumpreq, &variax->line6, 0,
162                 VARIAX_DUMP_PASS1);
163    /* passes 2 and 3 are performed implicitly before entering variax_startup6 */
164}
165
166static void variax_startup6(struct usb_line6_variax *variax)
167{
168    CHECK_STARTUP_PROGRESS(variax->startup_progress,
169                   VARIAX_STARTUP_WORKQUEUE);
170
171    /* schedule work for global work queue: */
172    schedule_work(&variax->startup_work);
173}
174
175static void variax_startup7(struct work_struct *work)
176{
177    struct usb_line6_variax *variax =
178        container_of(work, struct usb_line6_variax, startup_work);
179    struct usb_line6 *line6 = &variax->line6;
180
181    CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
182
183    /* ALSA audio interface: */
184    line6_register_audio(&variax->line6);
185
186    /* device files: */
187    line6_variax_create_files(0, 0, line6->ifcdev);
188    variax_create_files2(line6->ifcdev);
189}
190
191/*
192    Process a completely received message.
193*/
194void line6_variax_process_message(struct usb_line6_variax *variax)
195{
196    const unsigned char *buf = variax->line6.buffer_message;
197
198    switch (buf[0]) {
199    case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
200        switch (buf[1]) {
201        case VARIAXMIDI_volume:
202            variax->volume = buf[2];
203            break;
204
205        case VARIAXMIDI_tone:
206            variax->tone = buf[2];
207        }
208
209        break;
210
211    case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
212    case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
213        variax->model = buf[1];
214        line6_dump_request_async(&variax->dumpreq, &variax->line6, 0,
215                     VARIAX_DUMP_PASS1);
216        break;
217
218    case LINE6_RESET:
219        dev_info(variax->line6.ifcdev, "VARIAX reset\n");
220        break;
221
222    case LINE6_SYSEX_BEGIN:
223        if (memcmp(buf + 1, variax_request_model1 + 1,
224               VARIAX_MODEL_HEADER_LENGTH - 1) == 0) {
225            if (variax->line6.message_length ==
226                VARIAX_MODEL_MESSAGE_LENGTH) {
227                switch (variax->dumpreq.in_progress) {
228                case VARIAX_DUMP_PASS1:
229                    variax_decode(buf +
230                              VARIAX_MODEL_HEADER_LENGTH,
231                              (unsigned char *)
232                              &variax->model_data,
233                              (sizeof
234                               (variax->model_data.
235                            name) +
236                               sizeof(variax->
237                                  model_data.
238                                  control)
239                               / 2) * 2);
240                    line6_dump_request_async
241                        (&variax->dumpreq, &variax->line6,
242                         1, VARIAX_DUMP_PASS2);
243                    break;
244
245                case VARIAX_DUMP_PASS2:
246                    /* model name is transmitted twice, so skip it here: */
247                    variax_decode(buf +
248                              VARIAX_MODEL_HEADER_LENGTH,
249                              (unsigned char *)
250                              &variax->
251                              model_data.control +
252                              sizeof(variax->model_data.
253                                 control)
254                              / 2,
255                              sizeof(variax->model_data.
256                                 control)
257                              / 2 * 2);
258                    line6_dump_request_async
259                        (&variax->dumpreq, &variax->line6,
260                         2, VARIAX_DUMP_PASS3);
261                }
262            } else {
263                DEBUG_MESSAGES(dev_err
264                           (variax->line6.ifcdev,
265                        "illegal length %d of model data\n",
266                        variax->line6.message_length));
267                line6_dump_finished(&variax->dumpreq);
268            }
269        } else if (memcmp(buf + 1, variax_request_bank + 1,
270                  sizeof(variax_request_bank) - 2) == 0) {
271            memcpy(variax->bank,
272                   buf + sizeof(variax_request_bank) - 1,
273                   sizeof(variax->bank));
274            line6_dump_finished(&variax->dumpreq);
275            variax_startup6(variax);
276        } else if (memcmp(buf + 1, variax_init_model + 1,
277                  sizeof(variax_init_model) - 1) == 0) {
278            memcpy(variax->guitar,
279                   buf + sizeof(variax_init_model),
280                   sizeof(variax->guitar));
281        } else if (memcmp(buf + 1, variax_init_version + 1,
282                  sizeof(variax_init_version) - 1) == 0) {
283            variax_startup3(variax);
284        } else if (memcmp(buf + 1, variax_init_done + 1,
285                  sizeof(variax_init_done) - 1) == 0) {
286            /* notify of complete initialization: */
287            variax_startup4((unsigned long)variax);
288        }
289
290        break;
291
292    case LINE6_SYSEX_END:
293        break;
294
295    default:
296        DEBUG_MESSAGES(dev_err
297                   (variax->line6.ifcdev,
298                "Variax: unknown message %02X\n", buf[0]));
299    }
300}
301
302/*
303    "read" request on "volume" special file.
304*/
305static ssize_t variax_get_volume(struct device *dev,
306                 struct device_attribute *attr, char *buf)
307{
308    struct usb_line6_variax *variax =
309        usb_get_intfdata(to_usb_interface(dev));
310    return sprintf(buf, "%d\n", variax->volume);
311}
312
313/*
314    "write" request on "volume" special file.
315*/
316static ssize_t variax_set_volume(struct device *dev,
317                 struct device_attribute *attr,
318                 const char *buf, size_t count)
319{
320    struct usb_line6_variax *variax =
321        usb_get_intfdata(to_usb_interface(dev));
322    u8 value;
323    int ret;
324
325    ret = kstrtou8(buf, 10, &value);
326    if (ret)
327        return ret;
328
329    if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_volume,
330                     value) == 0)
331        variax->volume = value;
332
333    return count;
334}
335
336/*
337    "read" request on "model" special file.
338*/
339static ssize_t variax_get_model(struct device *dev,
340                struct device_attribute *attr, char *buf)
341{
342    struct usb_line6_variax *variax =
343        usb_get_intfdata(to_usb_interface(dev));
344    return sprintf(buf, "%d\n", variax->model);
345}
346
347/*
348    "write" request on "model" special file.
349*/
350static ssize_t variax_set_model(struct device *dev,
351                struct device_attribute *attr,
352                const char *buf, size_t count)
353{
354    struct usb_line6_variax *variax =
355        usb_get_intfdata(to_usb_interface(dev));
356    unsigned long value;
357    int ret;
358
359    ret = strict_strtoul(buf, 10, &value);
360    if (ret)
361        return ret;
362
363    if (line6_send_program(&variax->line6, value) == 0)
364        variax->model = value;
365
366    return count;
367}
368
369/*
370    "read" request on "active" special file.
371*/
372static ssize_t variax_get_active(struct device *dev,
373                 struct device_attribute *attr, char *buf)
374{
375    struct usb_line6_variax *variax =
376        usb_get_intfdata(to_usb_interface(dev));
377    return sprintf(buf, "%d\n",
378               variax->buffer_activate[VARIAX_OFFSET_ACTIVATE]);
379}
380
381/*
382    "write" request on "active" special file.
383*/
384static ssize_t variax_set_active(struct device *dev,
385                 struct device_attribute *attr,
386                 const char *buf, size_t count)
387{
388    struct usb_line6_variax *variax =
389        usb_get_intfdata(to_usb_interface(dev));
390    unsigned long value;
391    int ret;
392
393    ret = strict_strtoul(buf, 10, &value);
394    if (ret)
395        return ret;
396
397    variax_activate_async(variax, value ? 1 : 0);
398    return count;
399}
400
401/*
402    "read" request on "tone" special file.
403*/
404static ssize_t variax_get_tone(struct device *dev,
405                   struct device_attribute *attr, char *buf)
406{
407    struct usb_line6_variax *variax =
408        usb_get_intfdata(to_usb_interface(dev));
409    return sprintf(buf, "%d\n", variax->tone);
410}
411
412/*
413    "write" request on "tone" special file.
414*/
415static ssize_t variax_set_tone(struct device *dev,
416                   struct device_attribute *attr,
417                   const char *buf, size_t count)
418{
419    struct usb_line6_variax *variax =
420        usb_get_intfdata(to_usb_interface(dev));
421    u8 value;
422    int ret;
423
424    ret = kstrtou8(buf, 10, &value);
425    if (ret)
426        return ret;
427
428    if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_tone,
429                     value) == 0)
430        variax->tone = value;
431
432    return count;
433}
434
435static ssize_t get_string(char *buf, const char *data, int length)
436{
437    int i;
438    memcpy(buf, data, length);
439
440    for (i = length; i--;) {
441        char c = buf[i];
442
443        if ((c != 0) && (c != ' '))
444            break;
445    }
446
447    buf[i + 1] = '\n';
448    return i + 2;
449}
450
451/*
452    "read" request on "name" special file.
453*/
454static ssize_t variax_get_name(struct device *dev,
455                   struct device_attribute *attr, char *buf)
456{
457    struct usb_line6_variax *variax =
458        usb_get_intfdata(to_usb_interface(dev));
459    line6_dump_wait_interruptible(&variax->dumpreq);
460    return get_string(buf, variax->model_data.name,
461              sizeof(variax->model_data.name));
462}
463
464/*
465    "read" request on "bank" special file.
466*/
467static ssize_t variax_get_bank(struct device *dev,
468                   struct device_attribute *attr, char *buf)
469{
470    struct usb_line6_variax *variax =
471        usb_get_intfdata(to_usb_interface(dev));
472    line6_dump_wait_interruptible(&variax->dumpreq);
473    return get_string(buf, variax->bank, sizeof(variax->bank));
474}
475
476/*
477    "read" request on "dump" special file.
478*/
479static ssize_t variax_get_dump(struct device *dev,
480                   struct device_attribute *attr, char *buf)
481{
482    struct usb_line6_variax *variax =
483        usb_get_intfdata(to_usb_interface(dev));
484    int retval;
485    retval = line6_dump_wait_interruptible(&variax->dumpreq);
486    if (retval < 0)
487        return retval;
488    memcpy(buf, &variax->model_data.control,
489           sizeof(variax->model_data.control));
490    return sizeof(variax->model_data.control);
491}
492
493/*
494    "read" request on "guitar" special file.
495*/
496static ssize_t variax_get_guitar(struct device *dev,
497                 struct device_attribute *attr, char *buf)
498{
499    struct usb_line6_variax *variax =
500        usb_get_intfdata(to_usb_interface(dev));
501    return sprintf(buf, "%s\n", variax->guitar);
502}
503
504#ifdef CONFIG_LINE6_USB_RAW
505
506static char *variax_alloc_sysex_buffer(struct usb_line6_variax *variax,
507                       int code, int size)
508{
509    return line6_alloc_sysex_buffer(&variax->line6, VARIAX_SYSEX_CODE, code,
510                    size);
511}
512
513/*
514    "write" request on "raw" special file.
515*/
516static ssize_t variax_set_raw2(struct device *dev,
517                   struct device_attribute *attr,
518                   const char *buf, size_t count)
519{
520    struct usb_line6_variax *variax =
521        usb_get_intfdata(to_usb_interface(dev));
522    int size;
523    int i;
524    char *sysex;
525
526    count -= count % 3;
527    size = count * 2;
528    sysex = variax_alloc_sysex_buffer(variax, VARIAX_SYSEX_PARAM, size);
529
530    if (!sysex)
531        return 0;
532
533    for (i = 0; i < count; i += 3) {
534        const unsigned char *p1 = buf + i;
535        char *p2 = sysex + SYSEX_DATA_OFS + i * 2;
536        p2[0] = p1[2] & 0x0f;
537        p2[1] = p1[2] >> 4;
538        p2[2] = p1[1] & 0x0f;
539        p2[3] = p1[1] >> 4;
540        p2[4] = p1[0] & 0x0f;
541        p2[5] = p1[0] >> 4;
542    }
543
544    line6_send_sysex_message(&variax->line6, sysex, size);
545    kfree(sysex);
546    return count;
547}
548
549#endif
550
551/* Variax workbench special files: */
552static DEVICE_ATTR(model, S_IWUSR | S_IRUGO, variax_get_model,
553           variax_set_model);
554static DEVICE_ATTR(volume, S_IWUSR | S_IRUGO, variax_get_volume,
555           variax_set_volume);
556static DEVICE_ATTR(tone, S_IWUSR | S_IRUGO, variax_get_tone, variax_set_tone);
557static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
558static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
559static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
560static DEVICE_ATTR(active, S_IWUSR | S_IRUGO, variax_get_active,
561           variax_set_active);
562static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write);
563
564#ifdef CONFIG_LINE6_USB_RAW
565static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
566static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2);
567#endif
568
569/*
570    Variax destructor.
571*/
572static void variax_destruct(struct usb_interface *interface)
573{
574    struct usb_line6_variax *variax = usb_get_intfdata(interface);
575
576    if (variax == NULL)
577        return;
578    line6_cleanup_audio(&variax->line6);
579
580    del_timer(&variax->startup_timer1);
581    del_timer(&variax->startup_timer2);
582    cancel_work_sync(&variax->startup_work);
583
584    /* free dump request data: */
585    line6_dumpreq_destructbuf(&variax->dumpreq, 2);
586    line6_dumpreq_destructbuf(&variax->dumpreq, 1);
587    line6_dumpreq_destruct(&variax->dumpreq);
588
589    kfree(variax->buffer_activate);
590}
591
592/*
593    Create sysfs entries.
594*/
595static int variax_create_files2(struct device *dev)
596{
597    int err;
598    CHECK_RETURN(device_create_file(dev, &dev_attr_model));
599    CHECK_RETURN(device_create_file(dev, &dev_attr_volume));
600    CHECK_RETURN(device_create_file(dev, &dev_attr_tone));
601    CHECK_RETURN(device_create_file(dev, &dev_attr_name));
602    CHECK_RETURN(device_create_file(dev, &dev_attr_bank));
603    CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
604    CHECK_RETURN(device_create_file(dev, &dev_attr_active));
605    CHECK_RETURN(device_create_file(dev, &dev_attr_guitar));
606#ifdef CONFIG_LINE6_USB_RAW
607    CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
608    CHECK_RETURN(device_create_file(dev, &dev_attr_raw2));
609#endif
610    return 0;
611}
612
613/*
614     Try to init workbench device.
615*/
616static int variax_try_init(struct usb_interface *interface,
617               struct usb_line6_variax *variax)
618{
619    int err;
620
621    init_timer(&variax->startup_timer1);
622    init_timer(&variax->startup_timer2);
623    INIT_WORK(&variax->startup_work, variax_startup7);
624
625    if ((interface == NULL) || (variax == NULL))
626        return -ENODEV;
627
628    /* initialize USB buffers: */
629    err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1,
630                 sizeof(variax_request_model1));
631
632    if (err < 0) {
633        dev_err(&interface->dev, "Out of memory\n");
634        return err;
635    }
636
637    err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2,
638                    sizeof(variax_request_model2), 1);
639
640    if (err < 0) {
641        dev_err(&interface->dev, "Out of memory\n");
642        return err;
643    }
644
645    err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank,
646                    sizeof(variax_request_bank), 2);
647
648    if (err < 0) {
649        dev_err(&interface->dev, "Out of memory\n");
650        return err;
651    }
652
653    variax->buffer_activate = kmemdup(variax_activate,
654                      sizeof(variax_activate), GFP_KERNEL);
655
656    if (variax->buffer_activate == NULL) {
657        dev_err(&interface->dev, "Out of memory\n");
658        return -ENOMEM;
659    }
660
661    /* initialize audio system: */
662    err = line6_init_audio(&variax->line6);
663    if (err < 0)
664        return err;
665
666    /* initialize MIDI subsystem: */
667    err = line6_init_midi(&variax->line6);
668    if (err < 0)
669        return err;
670
671    /* initiate startup procedure: */
672    variax_startup1(variax);
673    return 0;
674}
675
676/*
677     Init workbench device (and clean up in case of failure).
678*/
679int line6_variax_init(struct usb_interface *interface,
680              struct usb_line6_variax *variax)
681{
682    int err = variax_try_init(interface, variax);
683
684    if (err < 0)
685        variax_destruct(interface);
686
687    return err;
688}
689
690/*
691    Workbench device disconnected.
692*/
693void line6_variax_disconnect(struct usb_interface *interface)
694{
695    struct device *dev;
696
697    if (interface == NULL)
698        return;
699    dev = &interface->dev;
700
701    if (dev != NULL) {
702        /* remove sysfs entries: */
703        line6_variax_remove_files(0, 0, dev);
704        device_remove_file(dev, &dev_attr_model);
705        device_remove_file(dev, &dev_attr_volume);
706        device_remove_file(dev, &dev_attr_tone);
707        device_remove_file(dev, &dev_attr_name);
708        device_remove_file(dev, &dev_attr_bank);
709        device_remove_file(dev, &dev_attr_dump);
710        device_remove_file(dev, &dev_attr_active);
711        device_remove_file(dev, &dev_attr_guitar);
712#ifdef CONFIG_LINE6_USB_RAW
713        device_remove_file(dev, &dev_attr_raw);
714        device_remove_file(dev, &dev_attr_raw2);
715#endif
716    }
717
718    variax_destruct(interface);
719}
720

Archive Download this file



interactive