]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/line6/variax.c
Merge branch 'fixes' of git://ftp.arm.linux.org.uk/~rmk/linux-arm
[mirror_ubuntu-artful-kernel.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
99 CHECK_STARTUP_PROGRESS(variax->startup_progress,
100 VARIAX_STARTUP_ACTIVATE);
101
102 /* activate device: */
103 variax_activate_async(variax, 1);
104 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
105 variax_startup5, (unsigned long)variax);
106 }
107
108 static void variax_startup5(unsigned long data)
109 {
110 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
111
112 CHECK_STARTUP_PROGRESS(variax->startup_progress,
113 VARIAX_STARTUP_WORKQUEUE);
114
115 /* schedule work for global work queue: */
116 schedule_work(&variax->startup_work);
117 }
118
119 static void variax_startup6(struct work_struct *work)
120 {
121 struct usb_line6_variax *variax =
122 container_of(work, struct usb_line6_variax, startup_work);
123
124 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
125
126 /* ALSA audio interface: */
127 line6_register_audio(&variax->line6);
128 }
129
130 /*
131 Process a completely received message.
132 */
133 void line6_variax_process_message(struct usb_line6_variax *variax)
134 {
135 const unsigned char *buf = variax->line6.buffer_message;
136
137 switch (buf[0]) {
138 case LINE6_RESET:
139 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
140 break;
141
142 case LINE6_SYSEX_BEGIN:
143 if (memcmp(buf + 1, variax_init_version + 1,
144 sizeof(variax_init_version) - 1) == 0) {
145 variax_startup3(variax);
146 } else if (memcmp(buf + 1, variax_init_done + 1,
147 sizeof(variax_init_done) - 1) == 0) {
148 /* notify of complete initialization: */
149 variax_startup4((unsigned long)variax);
150 }
151 break;
152 }
153 }
154
155 /*
156 Variax destructor.
157 */
158 static void variax_destruct(struct usb_interface *interface)
159 {
160 struct usb_line6_variax *variax = usb_get_intfdata(interface);
161
162 if (variax == NULL)
163 return;
164 line6_cleanup_audio(&variax->line6);
165
166 del_timer(&variax->startup_timer1);
167 del_timer(&variax->startup_timer2);
168 cancel_work_sync(&variax->startup_work);
169
170 kfree(variax->buffer_activate);
171 }
172
173 /*
174 Try to init workbench device.
175 */
176 static int variax_try_init(struct usb_interface *interface,
177 struct usb_line6_variax *variax)
178 {
179 int err;
180
181 init_timer(&variax->startup_timer1);
182 init_timer(&variax->startup_timer2);
183 INIT_WORK(&variax->startup_work, variax_startup6);
184
185 if ((interface == NULL) || (variax == NULL))
186 return -ENODEV;
187
188 /* initialize USB buffers: */
189 variax->buffer_activate = kmemdup(variax_activate,
190 sizeof(variax_activate), GFP_KERNEL);
191
192 if (variax->buffer_activate == NULL) {
193 dev_err(&interface->dev, "Out of memory\n");
194 return -ENOMEM;
195 }
196
197 /* initialize audio system: */
198 err = line6_init_audio(&variax->line6);
199 if (err < 0)
200 return err;
201
202 /* initialize MIDI subsystem: */
203 err = line6_init_midi(&variax->line6);
204 if (err < 0)
205 return err;
206
207 /* initiate startup procedure: */
208 variax_startup1(variax);
209 return 0;
210 }
211
212 /*
213 Init workbench device (and clean up in case of failure).
214 */
215 int line6_variax_init(struct usb_interface *interface,
216 struct usb_line6_variax *variax)
217 {
218 int err = variax_try_init(interface, variax);
219
220 if (err < 0)
221 variax_destruct(interface);
222
223 return err;
224 }
225
226 /*
227 Workbench device disconnected.
228 */
229 void line6_variax_disconnect(struct usb_interface *interface)
230 {
231 if (interface == NULL)
232 return;
233
234 variax_destruct(interface);
235 }