Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[firefly-linux-kernel-4.4.55.git] / 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 "driver.h"
16 #include "variax.h"
17
18 #define VARIAX_OFFSET_ACTIVATE 7
19
20 /*
21         This message is sent by the device during initialization and identifies
22         the connected guitar version.
23 */
24 static const char variax_init_version[] = {
25         0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
26         0x07, 0x00, 0x00, 0x00
27 };
28
29 /*
30         This message is the last one sent by the device during initialization.
31 */
32 static const char variax_init_done[] = {
33         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
34 };
35
36 static const char variax_activate[] = {
37         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
38         0xf7
39 };
40
41 /* forward declarations: */
42 static void variax_startup2(unsigned long data);
43 static void variax_startup4(unsigned long data);
44 static void variax_startup5(unsigned long data);
45
46 static void variax_activate_async(struct usb_line6_variax *variax, int a)
47 {
48         variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
49         line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
50                                      sizeof(variax_activate));
51 }
52
53 /*
54         Variax startup procedure.
55         This is a sequence of functions with special requirements (e.g., must
56         not run immediately after initialization, must not run in interrupt
57         context). After the last one has finished, the device is ready to use.
58 */
59
60 static void variax_startup1(struct usb_line6_variax *variax)
61 {
62         CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
63
64         /* delay startup procedure: */
65         line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
66                           variax_startup2, (unsigned long)variax);
67 }
68
69 static void variax_startup2(unsigned long data)
70 {
71         struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
72         struct usb_line6 *line6 = &variax->line6;
73
74         /* schedule another startup procedure until startup is complete: */
75         if (variax->startup_progress >= VARIAX_STARTUP_LAST)
76                 return;
77
78         variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
79         line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
80                           variax_startup2, (unsigned long)variax);
81
82         /* request firmware version: */
83         line6_version_request_async(line6);
84 }
85
86 static void variax_startup3(struct usb_line6_variax *variax)
87 {
88         CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
89
90         /* delay startup procedure: */
91         line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
92                           variax_startup4, (unsigned long)variax);
93 }
94
95 static void variax_startup4(unsigned long data)
96 {
97         struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
98         CHECK_STARTUP_PROGRESS(variax->startup_progress,
99                                VARIAX_STARTUP_ACTIVATE);
100
101         /* activate device: */
102         variax_activate_async(variax, 1);
103         line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
104                           variax_startup5, (unsigned long)variax);
105 }
106
107 static void variax_startup5(unsigned long data)
108 {
109         struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
110         CHECK_STARTUP_PROGRESS(variax->startup_progress,
111                                VARIAX_STARTUP_WORKQUEUE);
112
113         /* schedule work for global work queue: */
114         schedule_work(&variax->startup_work);
115 }
116
117 static void variax_startup6(struct work_struct *work)
118 {
119         struct usb_line6_variax *variax =
120             container_of(work, struct usb_line6_variax, startup_work);
121
122         CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
123
124         /* ALSA audio interface: */
125         line6_register_audio(&variax->line6);
126 }
127
128 /*
129         Process a completely received message.
130 */
131 void line6_variax_process_message(struct usb_line6_variax *variax)
132 {
133         const unsigned char *buf = variax->line6.buffer_message;
134
135         switch (buf[0]) {
136         case LINE6_RESET:
137                 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
138                 break;
139
140         case LINE6_SYSEX_BEGIN:
141                 if (memcmp(buf + 1, variax_init_version + 1,
142                            sizeof(variax_init_version) - 1) == 0) {
143                         variax_startup3(variax);
144                 } else if (memcmp(buf + 1, variax_init_done + 1,
145                                   sizeof(variax_init_done) - 1) == 0) {
146                         /* notify of complete initialization: */
147                         variax_startup4((unsigned long)variax);
148                 }
149                 break;
150         }
151 }
152
153 /*
154         Variax destructor.
155 */
156 static void variax_destruct(struct usb_interface *interface)
157 {
158         struct usb_line6_variax *variax = usb_get_intfdata(interface);
159
160         if (variax == NULL)
161                 return;
162         line6_cleanup_audio(&variax->line6);
163
164         del_timer(&variax->startup_timer1);
165         del_timer(&variax->startup_timer2);
166         cancel_work_sync(&variax->startup_work);
167
168         kfree(variax->buffer_activate);
169 }
170
171 /*
172          Try to init workbench device.
173 */
174 static int variax_try_init(struct usb_interface *interface,
175                            struct usb_line6_variax *variax)
176 {
177         int err;
178
179         init_timer(&variax->startup_timer1);
180         init_timer(&variax->startup_timer2);
181         INIT_WORK(&variax->startup_work, variax_startup6);
182
183         if ((interface == NULL) || (variax == NULL))
184                 return -ENODEV;
185
186         /* initialize USB buffers: */
187         variax->buffer_activate = kmemdup(variax_activate,
188                                           sizeof(variax_activate), GFP_KERNEL);
189
190         if (variax->buffer_activate == NULL) {
191                 dev_err(&interface->dev, "Out of memory\n");
192                 return -ENOMEM;
193         }
194
195         /* initialize audio system: */
196         err = line6_init_audio(&variax->line6);
197         if (err < 0)
198                 return err;
199
200         /* initialize MIDI subsystem: */
201         err = line6_init_midi(&variax->line6);
202         if (err < 0)
203                 return err;
204
205         /* initiate startup procedure: */
206         variax_startup1(variax);
207         return 0;
208 }
209
210 /*
211          Init workbench device (and clean up in case of failure).
212 */
213 int line6_variax_init(struct usb_interface *interface,
214                       struct usb_line6_variax *variax)
215 {
216         int err = variax_try_init(interface, variax);
217
218         if (err < 0)
219                 variax_destruct(interface);
220
221         return err;
222 }
223
224 /*
225         Workbench device disconnected.
226 */
227 void line6_variax_disconnect(struct usb_interface *interface)
228 {
229         if (interface == NULL)
230                 return;
231
232         variax_destruct(interface);
233 }