xref: /openbmc/linux/sound/usb/line6/variax.c (revision 85a9339becf0af4d547ceb6bb16d1893b05fbce4)
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 #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 Line6 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");
335