blob: 0c852bb1e76c5c3e2d84fa614accb760dcb9c894 [file] [log] [blame]
Markus Grabner705ecec2009-02-27 19:43:04 -08001/*
Markus Grabnere1a164d2010-08-23 01:08:25 +02002 * Line6 Linux USB driver - 0.9.1beta
Markus Grabner705ecec2009-02-27 19:43:04 -08003 *
Markus Grabner1027f472010-08-12 01:35:30 +02004 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
Markus Grabner705ecec2009-02-27 19:43:04 -08005 *
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
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Takashi Iwaiccddbe42015-01-15 08:22:31 +010013#include <linux/spinlock.h>
14#include <linux/usb.h>
15#include <linux/wait.h>
16#include <linux/module.h>
17#include <sound/core.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090018
Markus Grabner705ecec2009-02-27 19:43:04 -080019#include "audio.h"
Markus Grabner1027f472010-08-12 01:35:30 +020020#include "driver.h"
Takashi Iwaiccddbe42015-01-15 08:22:31 +010021#include "usbdefs.h"
22
23#define VARIAX_STARTUP_DELAY1 1000
24#define VARIAX_STARTUP_DELAY3 100
25#define VARIAX_STARTUP_DELAY4 100
26
27/*
28 Stages of Variax startup procedure
29*/
30enum {
31 VARIAX_STARTUP_INIT = 1,
32 VARIAX_STARTUP_VERSIONREQ,
33 VARIAX_STARTUP_WAIT,
34 VARIAX_STARTUP_ACTIVATE,
35 VARIAX_STARTUP_WORKQUEUE,
36 VARIAX_STARTUP_SETUP,
37 VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
38};
39
40enum {
41 LINE6_PODXTLIVE_VARIAX,
42 LINE6_VARIAX
43};
44
45struct usb_line6_variax {
46 /**
47 Generic Line6 USB data.
48 */
49 struct usb_line6 line6;
50
51 /**
52 Buffer for activation code.
53 */
54 unsigned char *buffer_activate;
55
56 /**
57 Handler for device initializaton.
58 */
59 struct work_struct startup_work;
60
61 /**
62 Timers for device initializaton.
63 */
64 struct timer_list startup_timer1;
65 struct timer_list startup_timer2;
66
67 /**
68 Current progress in startup procedure.
69 */
70 int startup_progress;
71};
Markus Grabner705ecec2009-02-27 19:43:04 -080072
Markus Grabner705ecec2009-02-27 19:43:04 -080073#define VARIAX_OFFSET_ACTIVATE 7
74
Markus Grabner1027f472010-08-12 01:35:30 +020075/*
76 This message is sent by the device during initialization and identifies
Markus Grabner1027f472010-08-12 01:35:30 +020077 the connected guitar version.
78*/
79static const char variax_init_version[] = {
80 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
81 0x07, 0x00, 0x00, 0x00
82};
83
84/*
85 This message is the last one sent by the device during initialization.
86*/
87static const char variax_init_done[] = {
88 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
89};
90
Markus Grabner705ecec2009-02-27 19:43:04 -080091static const char variax_activate[] = {
92 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
93 0xf7
94};
Markus Grabner1027f472010-08-12 01:35:30 +020095
Markus Grabner1027f472010-08-12 01:35:30 +020096/* forward declarations: */
Markus Grabner1027f472010-08-12 01:35:30 +020097static void variax_startup2(unsigned long data);
98static void variax_startup4(unsigned long data);
99static void variax_startup5(unsigned long data);
100
Markus Grabner1027f472010-08-12 01:35:30 +0200101static void variax_activate_async(struct usb_line6_variax *variax, int a)
Markus Grabner705ecec2009-02-27 19:43:04 -0800102{
Markus Grabner1027f472010-08-12 01:35:30 +0200103 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800104 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
105 sizeof(variax_activate));
Markus Grabner705ecec2009-02-27 19:43:04 -0800106}
107
108/*
Markus Grabner1027f472010-08-12 01:35:30 +0200109 Variax startup procedure.
110 This is a sequence of functions with special requirements (e.g., must
111 not run immediately after initialization, must not run in interrupt
112 context). After the last one has finished, the device is ready to use.
Markus Grabner705ecec2009-02-27 19:43:04 -0800113*/
Markus Grabner1027f472010-08-12 01:35:30 +0200114
115static void variax_startup1(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800116{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200117 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200118
119 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200120 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
121 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800122}
123
Markus Grabner1027f472010-08-12 01:35:30 +0200124static void variax_startup2(unsigned long data)
Markus Grabner705ecec2009-02-27 19:43:04 -0800125{
Markus Grabner1027f472010-08-12 01:35:30 +0200126 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
127 struct usb_line6 *line6 = &variax->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200128
129 /* schedule another startup procedure until startup is complete: */
130 if (variax->startup_progress >= VARIAX_STARTUP_LAST)
131 return;
132
133 variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
134 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
135 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800136
Markus Grabner1027f472010-08-12 01:35:30 +0200137 /* request firmware version: */
138 line6_version_request_async(line6);
139}
Markus Grabner705ecec2009-02-27 19:43:04 -0800140
Markus Grabner1027f472010-08-12 01:35:30 +0200141static void variax_startup3(struct usb_line6_variax *variax)
142{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200143 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200144
145 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200146 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
147 variax_startup4, (unsigned long)variax);
Markus Grabner1027f472010-08-12 01:35:30 +0200148}
149
150static void variax_startup4(unsigned long data)
151{
152 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700153
Markus Grabnere1a164d2010-08-23 01:08:25 +0200154 CHECK_STARTUP_PROGRESS(variax->startup_progress,
155 VARIAX_STARTUP_ACTIVATE);
Markus Grabner1027f472010-08-12 01:35:30 +0200156
157 /* activate device: */
158 variax_activate_async(variax, 1);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200159 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
160 variax_startup5, (unsigned long)variax);
Markus Grabner1027f472010-08-12 01:35:30 +0200161}
162
163static void variax_startup5(unsigned long data)
164{
165 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700166
Markus Grabnere1a164d2010-08-23 01:08:25 +0200167 CHECK_STARTUP_PROGRESS(variax->startup_progress,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200168 VARIAX_STARTUP_WORKQUEUE);
Markus Grabner1027f472010-08-12 01:35:30 +0200169
170 /* schedule work for global work queue: */
171 schedule_work(&variax->startup_work);
172}
173
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100174static void variax_startup6(struct work_struct *work)
Markus Grabner1027f472010-08-12 01:35:30 +0200175{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200176 struct usb_line6_variax *variax =
177 container_of(work, struct usb_line6_variax, startup_work);
Markus Grabner1027f472010-08-12 01:35:30 +0200178
Markus Grabnere1a164d2010-08-23 01:08:25 +0200179 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
Markus Grabner1027f472010-08-12 01:35:30 +0200180
181 /* ALSA audio interface: */
182 line6_register_audio(&variax->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800183}
184
185/*
186 Process a completely received message.
187*/
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800188static void line6_variax_process_message(struct usb_line6 *line6)
Markus Grabner705ecec2009-02-27 19:43:04 -0800189{
Chris Rorvick1cad3e82015-01-12 12:42:57 -0800190 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800191 const unsigned char *buf = variax->line6.buffer_message;
192
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800193 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800194 case LINE6_RESET:
195 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800196 break;
197
198 case LINE6_SYSEX_BEGIN:
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100199 if (memcmp(buf + 1, variax_init_version + 1,
200 sizeof(variax_init_version) - 1) == 0) {
Markus Grabner1027f472010-08-12 01:35:30 +0200201 variax_startup3(variax);
202 } else if (memcmp(buf + 1, variax_init_done + 1,
203 sizeof(variax_init_done) - 1) == 0) {
204 /* notify of complete initialization: */
205 variax_startup4((unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800206 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800207 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800208 }
209}
210
Markus Grabner705ecec2009-02-27 19:43:04 -0800211/*
212 Variax destructor.
213*/
214static void variax_destruct(struct usb_interface *interface)
215{
216 struct usb_line6_variax *variax = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800217
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800218 if (variax == NULL)
219 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100220 line6_cleanup_audio(&variax->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800221
Markus Grabnere1a164d2010-08-23 01:08:25 +0200222 del_timer(&variax->startup_timer1);
223 del_timer(&variax->startup_timer2);
224 cancel_work_sync(&variax->startup_work);
225
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800226 kfree(variax->buffer_activate);
Markus Grabner705ecec2009-02-27 19:43:04 -0800227}
228
229/*
Chris Rorvickd29b8542015-01-12 12:43:00 -0800230 Workbench device disconnected.
231*/
232static void line6_variax_disconnect(struct usb_interface *interface)
233{
234 if (interface == NULL)
235 return;
236
237 variax_destruct(interface);
238}
239
240/*
Markus Grabner1027f472010-08-12 01:35:30 +0200241 Try to init workbench device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800242*/
Markus Grabner1027f472010-08-12 01:35:30 +0200243static int variax_try_init(struct usb_interface *interface,
Chris Rorvicka221dd42015-01-12 12:42:56 -0800244 struct usb_line6 *line6)
Markus Grabner705ecec2009-02-27 19:43:04 -0800245{
Chris Rorvicka221dd42015-01-12 12:42:56 -0800246 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800247 int err;
248
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800249 line6->process_message = line6_variax_process_message;
Chris Rorvicka46c4672015-01-12 12:42:59 -0800250 line6->disconnect = line6_variax_disconnect;
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800251
Markus Grabnere1a164d2010-08-23 01:08:25 +0200252 init_timer(&variax->startup_timer1);
253 init_timer(&variax->startup_timer2);
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100254 INIT_WORK(&variax->startup_work, variax_startup6);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200255
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800256 if ((interface == NULL) || (variax == NULL))
257 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800258
259 /* initialize USB buffers: */
Julia Lawall94002c02010-05-15 23:21:43 +0200260 variax->buffer_activate = kmemdup(variax_activate,
261 sizeof(variax_activate), GFP_KERNEL);
Markus Grabner705ecec2009-02-27 19:43:04 -0800262
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800263 if (variax->buffer_activate == NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800264 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800265 return -ENOMEM;
266 }
267
Markus Grabner705ecec2009-02-27 19:43:04 -0800268 /* initialize audio system: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800269 err = line6_init_audio(&variax->line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700270 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800271 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800272
273 /* initialize MIDI subsystem: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800274 err = line6_init_midi(&variax->line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700275 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800276 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800277
Markus Grabner1027f472010-08-12 01:35:30 +0200278 /* initiate startup procedure: */
279 variax_startup1(variax);
280 return 0;
281}
282
283/*
284 Init workbench device (and clean up in case of failure).
285*/
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100286static int variax_init(struct usb_interface *interface,
287 struct usb_line6 *line6)
Markus Grabner1027f472010-08-12 01:35:30 +0200288{
Chris Rorvicka221dd42015-01-12 12:42:56 -0800289 int err = variax_try_init(interface, line6);
Markus Grabner1027f472010-08-12 01:35:30 +0200290
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700291 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800292 variax_destruct(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800293
Markus Grabner1027f472010-08-12 01:35:30 +0200294 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800295}
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100296
297#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
298#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
299
300/* table of devices that work with this driver */
301static const struct usb_device_id variax_id_table[] = {
302 { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
303 { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
304 {}
305};
306
307MODULE_DEVICE_TABLE(usb, variax_id_table);
308
309static const struct line6_properties variax_properties_table[] = {
310 [LINE6_PODXTLIVE_VARIAX] = {
311 .id = "PODxtLive",
312 .name = "PODxt Live",
313 .capabilities = LINE6_CAP_CONTROL
314 | LINE6_CAP_PCM
315 | LINE6_CAP_HWMON,
316 .altsetting = 1,
317 .ep_ctrl_r = 0x86,
318 .ep_ctrl_w = 0x05,
319 .ep_audio_r = 0x82,
320 .ep_audio_w = 0x01,
321 },
322 [LINE6_VARIAX] = {
323 .id = "Variax",
324 .name = "Variax Workbench",
325 .capabilities = LINE6_CAP_CONTROL,
326 .altsetting = 1,
327 .ep_ctrl_r = 0x82,
328 .ep_ctrl_w = 0x01,
329 /* no audio channel */
330 }
331};
332
333/*
334 Probe USB device.
335*/
336static int variax_probe(struct usb_interface *interface,
337 const struct usb_device_id *id)
338{
339 struct usb_line6_variax *variax;
340 int err;
341
342 variax = kzalloc(sizeof(*variax), GFP_KERNEL);
343 if (!variax)
344 return -ENODEV;
345 err = line6_probe(interface, &variax->line6,
346 &variax_properties_table[id->driver_info],
347 variax_init);
348 if (err < 0)
349 kfree(variax);
350 return err;
351}
352
353static struct usb_driver variax_driver = {
354 .name = KBUILD_MODNAME,
355 .probe = variax_probe,
356 .disconnect = line6_disconnect,
357#ifdef CONFIG_PM
358 .suspend = line6_suspend,
359 .resume = line6_resume,
360 .reset_resume = line6_resume,
361#endif
362 .id_table = variax_id_table,
363};
364
365module_usb_driver(variax_driver);
366
367MODULE_DESCRIPTION("Vairax Workbench USB driver");
368MODULE_LICENSE("GPL");