]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - sound/usb/line6/variax.c
99a58cbfd2da2b4047595d8d1c4e763165a3ba7f
[mirror_ubuntu-artful-kernel.git] / sound / usb / line6 / variax.c
1 /*
2 * Line 6 Linux USB driver
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 #include <linux/spinlock.h>
14 #include <linux/usb.h>
15 #include <linux/wait.h>
16 #include <linux/module.h>
17 #include <sound/core.h>
18
19 #include "driver.h"
20 #include "usbdefs.h"
21
22 #define VARIAX_STARTUP_DELAY1 1000
23 #define VARIAX_STARTUP_DELAY3 100
24 #define VARIAX_STARTUP_DELAY4 100
25
26 /*
27 Stages of Variax startup procedure
28 */
29 enum {
30 VARIAX_STARTUP_INIT = 1,
31 VARIAX_STARTUP_VERSIONREQ,
32 VARIAX_STARTUP_WAIT,
33 VARIAX_STARTUP_ACTIVATE,
34 VARIAX_STARTUP_WORKQUEUE,
35 VARIAX_STARTUP_SETUP,
36 VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
37 };
38
39 enum {
40 LINE6_PODXTLIVE_VARIAX,
41 LINE6_VARIAX
42 };
43
44 struct usb_line6_variax {
45 /**
46 Generic Line 6 USB data.
47 */
48 struct usb_line6 line6;
49
50 /**
51 Buffer for activation code.
52 */
53 unsigned char *buffer_activate;
54
55 /**
56 Handler for device initializaton.
57 */
58 struct work_struct startup_work;
59
60 /**
61 Timers for device initializaton.
62 */
63 struct timer_list startup_timer1;
64 struct timer_list startup_timer2;
65
66 /**
67 Current progress in startup procedure.
68 */
69 int startup_progress;
70 };
71
72 #define VARIAX_OFFSET_ACTIVATE 7
73
74 /*
75 This message is sent by the device during initialization and identifies
76 the connected guitar version.
77 */
78 static const char variax_init_version[] = {
79 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
80 0x07, 0x00, 0x00, 0x00
81 };
82
83 /*
84 This message is the last one sent by the device during initialization.
85 */
86 static const char variax_init_done[] = {
87 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
88 };
89
90 static const char variax_activate[] = {
91 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
92 0xf7
93 };
94
95 /* forward declarations: */
96 static void variax_startup2(unsigned long data);
97 static void variax_startup4(unsigned long data);
98 static void variax_startup5(unsigned long data);
99
100 static void variax_activate_async(struct usb_line6_variax *variax, int a)
101 {
102 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
103 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
104 sizeof(variax_activate));
105 }
106
107 /*
108 Variax startup procedure.
109 This is a sequence of functions with special requirements (e.g., must
110 not run immediately after initialization, must not run in interrupt
111 context). After the last one has finished, the device is ready to use.
112 */
113
114 static void variax_startup1(struct usb_line6_variax *variax)
115 {
116 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
117
118 /* delay startup procedure: */
119 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
120 variax_startup2, (unsigned long)variax);
121 }
122
123 static void variax_startup2(unsigned long data)
124 {
125 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
126 struct usb_line6 *line6 = &variax->line6;
127
128 /* schedule another startup procedure until startup is complete: */
129 if (variax->startup_progress >= VARIAX_STARTUP_LAST)
130 return;
131
132 variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
133 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
134 variax_startup2, (unsigned long)variax);
135
136 /* request firmware version: */
137 line6_version_request_async(line6);
138 }
139
140 static void variax_startup3(struct usb_line6_variax *variax)
141 {
142 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
143
144 /* delay startup procedure: */
145 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
146 variax_startup4, (unsigned long)variax);
147 }
148
149 static void variax_startup4(unsigned long data)
150 {
151 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
152
153 CHECK_STARTUP_PROGRESS(variax->startup_progress,
154 VARIAX_STARTUP_ACTIVATE);
155
156 /* activate device: */
157 variax_activate_async(variax, 1);
158 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
159 variax_startup5, (unsigned long)variax);
160 }
161
162 static void variax_startup5(unsigned long data)
163 {
164 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
165
166 CHECK_STARTUP_PROGRESS(variax->startup_progress,
167 VARIAX_STARTUP_WORKQUEUE);
168
169 /* schedule work for global work queue: */
170 schedule_work(&variax->startup_work);
171 }
172
173 static void variax_startup6(struct work_struct *work)
174 {
175 struct usb_line6_variax *variax =
176 container_of(work, struct usb_line6_variax, startup_work);
177
178 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
179
180 /* ALSA audio interface: */
181 snd_card_register(variax->line6.card);
182 }
183
184 /*
185 Process a completely received message.
186 */
187 static void line6_variax_process_message(struct usb_line6 *line6)
188 {
189 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
190 const unsigned char *buf = variax->line6.buffer_message;
191
192 switch (buf[0]) {
193 case LINE6_RESET:
194 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
195 break;
196
197 case LINE6_SYSEX_BEGIN:
198 if (memcmp(buf + 1, variax_init_version + 1,
199 sizeof(variax_init_version) - 1) == 0) {
200 variax_startup3(variax);
201 } else if (memcmp(buf + 1, variax_init_done + 1,
202 sizeof(variax_init_done) - 1) == 0) {
203 /* notify of complete initialization: */
204 variax_startup4((unsigned long)variax);
205 }
206 break;
207 }
208 }
209
210 /*
211 Variax destructor.
212 */
213 static void line6_variax_disconnect(struct usb_interface *interface)
214 {
215 struct usb_line6_variax *variax;
216
217 if (!interface)
218 return;
219
220 variax = usb_get_intfdata(interface);
221 if (!variax)
222 return;
223
224 del_timer(&variax->startup_timer1);
225 del_timer(&variax->startup_timer2);
226 cancel_work_sync(&variax->startup_work);
227
228 kfree(variax->buffer_activate);
229 }
230
231 /*
232 Try to init workbench device.
233 */
234 static int variax_init(struct usb_interface *interface,
235 struct usb_line6 *line6)
236 {
237 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
238 int err;
239
240 line6->process_message = line6_variax_process_message;
241 line6->disconnect = line6_variax_disconnect;
242
243 init_timer(&variax->startup_timer1);
244 init_timer(&variax->startup_timer2);
245 INIT_WORK(&variax->startup_work, variax_startup6);
246
247 if ((interface == NULL) || (variax == NULL))
248 return -ENODEV;
249
250 /* initialize USB buffers: */
251 variax->buffer_activate = kmemdup(variax_activate,
252 sizeof(variax_activate), GFP_KERNEL);
253
254 if (variax->buffer_activate == NULL)
255 return -ENOMEM;
256
257 /* initialize MIDI subsystem: */
258 err = line6_init_midi(&variax->line6);
259 if (err < 0)
260 return err;
261
262 /* initiate startup procedure: */
263 variax_startup1(variax);
264 return 0;
265 }
266
267 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
268 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
269
270 /* table of devices that work with this driver */
271 static const struct usb_device_id variax_id_table[] = {
272 { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
273 { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
274 {}
275 };
276
277 MODULE_DEVICE_TABLE(usb, variax_id_table);
278
279 static const struct line6_properties variax_properties_table[] = {
280 [LINE6_PODXTLIVE_VARIAX] = {
281 .id = "PODxtLive",
282 .name = "PODxt Live",
283 .capabilities = LINE6_CAP_CONTROL
284 | LINE6_CAP_PCM
285 | LINE6_CAP_HWMON,
286 .altsetting = 1,
287 .ep_ctrl_r = 0x86,
288 .ep_ctrl_w = 0x05,
289 .ep_audio_r = 0x82,
290 .ep_audio_w = 0x01,
291 },
292 [LINE6_VARIAX] = {
293 .id = "Variax",
294 .name = "Variax Workbench",
295 .capabilities = LINE6_CAP_CONTROL,
296 .altsetting = 1,
297 .ep_ctrl_r = 0x82,
298 .ep_ctrl_w = 0x01,
299 /* no audio channel */
300 }
301 };
302
303 /*
304 Probe USB device.
305 */
306 static int variax_probe(struct usb_interface *interface,
307 const struct usb_device_id *id)
308 {
309 struct usb_line6_variax *variax;
310
311 variax = kzalloc(sizeof(*variax), GFP_KERNEL);
312 if (!variax)
313 return -ENODEV;
314 return line6_probe(interface, &variax->line6,
315 &variax_properties_table[id->driver_info],
316 variax_init);
317 }
318
319 static struct usb_driver variax_driver = {
320 .name = KBUILD_MODNAME,
321 .probe = variax_probe,
322 .disconnect = line6_disconnect,
323 #ifdef CONFIG_PM
324 .suspend = line6_suspend,
325 .resume = line6_resume,
326 .reset_resume = line6_resume,
327 #endif
328 .id_table = variax_id_table,
329 };
330
331 module_usb_driver(variax_driver);
332
333 MODULE_DESCRIPTION("Vairax Workbench USB driver");
334 MODULE_LICENSE("GPL");