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