Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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*/
24static 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*/
32static const char variax_init_done[] = {
33 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
34};
35
36static const char variax_activate[] = {
37 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
38 0xf7
39};
40
41/* forward declarations: */
42static void variax_startup2(unsigned long data);
43static void variax_startup4(unsigned long data);
44static void variax_startup5(unsigned long data);
45
46static 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
60static 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
69static 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
86static 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
95static 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
107static 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
117static 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*/
131void 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*/
170static 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*/
188static 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*/
227int 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*/
241void line6_variax_disconnect(struct usb_interface *interface)
242{
243 if (interface == NULL)
244 return;
245
246 variax_destruct(interface);
247}