[SCSI] Merge tag 'fcoe-02-19-13' into for-linus
[cascardo/linux.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_PARAM_CHANGE | LINE6_CHANNEL_HOST:
137                 break;
138
139         case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
140         case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
141                 break;
142
143         case LINE6_RESET:
144                 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
145                 break;
146
147         case LINE6_SYSEX_BEGIN:
148                 if (memcmp(buf + 1, variax_init_version + 1,
149                            sizeof(variax_init_version) - 1) == 0) {
150                         variax_startup3(variax);
151                 } else if (memcmp(buf + 1, variax_init_done + 1,
152                                   sizeof(variax_init_done) - 1) == 0) {
153                         /* notify of complete initialization: */
154                         variax_startup4((unsigned long)variax);
155                 }
156                 break;
157
158         case LINE6_SYSEX_END:
159                 break;
160
161         default:
162                 dev_dbg(variax->line6.ifcdev,
163                         "Variax: unknown message %02X\n", buf[0]);
164         }
165 }
166
167 /*
168         Variax destructor.
169 */
170 static void variax_destruct(struct usb_interface *interface)
171 {
172         struct usb_line6_variax *variax = usb_get_intfdata(interface);
173
174         if (variax == NULL)
175                 return;
176         line6_cleanup_audio(&variax->line6);
177
178         del_timer(&variax->startup_timer1);
179         del_timer(&variax->startup_timer2);
180         cancel_work_sync(&variax->startup_work);
181
182         kfree(variax->buffer_activate);
183 }
184
185 /*
186          Try to init workbench device.
187 */
188 static int variax_try_init(struct usb_interface *interface,
189                            struct usb_line6_variax *variax)
190 {
191         int err;
192
193         init_timer(&variax->startup_timer1);
194         init_timer(&variax->startup_timer2);
195         INIT_WORK(&variax->startup_work, variax_startup6);
196
197         if ((interface == NULL) || (variax == NULL))
198                 return -ENODEV;
199
200         /* initialize USB buffers: */
201         variax->buffer_activate = kmemdup(variax_activate,
202                                           sizeof(variax_activate), GFP_KERNEL);
203
204         if (variax->buffer_activate == NULL) {
205                 dev_err(&interface->dev, "Out of memory\n");
206                 return -ENOMEM;
207         }
208
209         /* initialize audio system: */
210         err = line6_init_audio(&variax->line6);
211         if (err < 0)
212                 return err;
213
214         /* initialize MIDI subsystem: */
215         err = line6_init_midi(&variax->line6);
216         if (err < 0)
217                 return err;
218
219         /* initiate startup procedure: */
220         variax_startup1(variax);
221         return 0;
222 }
223
224 /*
225          Init workbench device (and clean up in case of failure).
226 */
227 int line6_variax_init(struct usb_interface *interface,
228                       struct usb_line6_variax *variax)
229 {
230         int err = variax_try_init(interface, variax);
231
232         if (err < 0)
233                 variax_destruct(interface);
234
235         return err;
236 }
237
238 /*
239         Workbench device disconnected.
240 */
241 void line6_variax_disconnect(struct usb_interface *interface)
242 {
243         if (interface == NULL)
244                 return;
245
246         variax_destruct(interface);
247 }