blob: 44042cbdef01b40c78b6aa255214cb7f2fb8db79 [file] [log] [blame]
Markus Grabner705ecec2009-02-27 19:43:04 -08001/*
Chris Rorvickc078a4a2015-01-20 02:20:50 -06002 * Line 6 Linux USB driver
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 Grabner1027f472010-08-12 01:35:30 +020019#include "driver.h"
Takashi Iwaiccddbe42015-01-15 08:22:31 +010020#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*/
29enum {
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
39enum {
40 LINE6_PODXTLIVE_VARIAX,
41 LINE6_VARIAX
42};
43
44struct usb_line6_variax {
Takashi Iwaicddbd4f2015-01-28 14:43:11 +010045 /* Generic Line 6 USB data */
Takashi Iwaiccddbe42015-01-15 08:22:31 +010046 struct usb_line6 line6;
47
Takashi Iwaicddbd4f2015-01-28 14:43:11 +010048 /* Buffer for activation code */
Takashi Iwaiccddbe42015-01-15 08:22:31 +010049 unsigned char *buffer_activate;
50
Takashi Iwaicddbd4f2015-01-28 14:43:11 +010051 /* Handler for device initialization */
Takashi Iwaiccddbe42015-01-15 08:22:31 +010052 struct work_struct startup_work;
53
Takashi Iwaicddbd4f2015-01-28 14:43:11 +010054 /* Timers for device initialization */
Takashi Iwaiccddbe42015-01-15 08:22:31 +010055 struct timer_list startup_timer1;
56 struct timer_list startup_timer2;
57
Takashi Iwaicddbd4f2015-01-28 14:43:11 +010058 /* Current progress in startup procedure */
Takashi Iwaiccddbe42015-01-15 08:22:31 +010059 int startup_progress;
60};
Markus Grabner705ecec2009-02-27 19:43:04 -080061
Markus Grabner705ecec2009-02-27 19:43:04 -080062#define VARIAX_OFFSET_ACTIVATE 7
63
Markus Grabner1027f472010-08-12 01:35:30 +020064/*
65 This message is sent by the device during initialization and identifies
Markus Grabner1027f472010-08-12 01:35:30 +020066 the connected guitar version.
67*/
68static const char variax_init_version[] = {
69 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
70 0x07, 0x00, 0x00, 0x00
71};
72
73/*
74 This message is the last one sent by the device during initialization.
75*/
76static const char variax_init_done[] = {
77 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
78};
79
Markus Grabner705ecec2009-02-27 19:43:04 -080080static const char variax_activate[] = {
81 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
82 0xf7
83};
Markus Grabner1027f472010-08-12 01:35:30 +020084
Markus Grabner1027f472010-08-12 01:35:30 +020085/* forward declarations: */
Markus Grabner1027f472010-08-12 01:35:30 +020086static void variax_startup2(unsigned long data);
87static void variax_startup4(unsigned long data);
88static void variax_startup5(unsigned long data);
89
Markus Grabner1027f472010-08-12 01:35:30 +020090static void variax_activate_async(struct usb_line6_variax *variax, int a)
Markus Grabner705ecec2009-02-27 19:43:04 -080091{
Markus Grabner1027f472010-08-12 01:35:30 +020092 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -080093 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
94 sizeof(variax_activate));
Markus Grabner705ecec2009-02-27 19:43:04 -080095}
96
97/*
Markus Grabner1027f472010-08-12 01:35:30 +020098 Variax startup procedure.
99 This is a sequence of functions with special requirements (e.g., must
100 not run immediately after initialization, must not run in interrupt
101 context). After the last one has finished, the device is ready to use.
Markus Grabner705ecec2009-02-27 19:43:04 -0800102*/
Markus Grabner1027f472010-08-12 01:35:30 +0200103
104static void variax_startup1(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800105{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200106 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200107
108 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200109 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
110 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800111}
112
Markus Grabner1027f472010-08-12 01:35:30 +0200113static void variax_startup2(unsigned long data)
Markus Grabner705ecec2009-02-27 19:43:04 -0800114{
Markus Grabner1027f472010-08-12 01:35:30 +0200115 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
116 struct usb_line6 *line6 = &variax->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200117
118 /* schedule another startup procedure until startup is complete: */
119 if (variax->startup_progress >= VARIAX_STARTUP_LAST)
120 return;
121
122 variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
123 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
124 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800125
Markus Grabner1027f472010-08-12 01:35:30 +0200126 /* request firmware version: */
127 line6_version_request_async(line6);
128}
Markus Grabner705ecec2009-02-27 19:43:04 -0800129
Markus Grabner1027f472010-08-12 01:35:30 +0200130static void variax_startup3(struct usb_line6_variax *variax)
131{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200132 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200133
134 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200135 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
136 variax_startup4, (unsigned long)variax);
Markus Grabner1027f472010-08-12 01:35:30 +0200137}
138
139static void variax_startup4(unsigned long data)
140{
141 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700142
Markus Grabnere1a164d2010-08-23 01:08:25 +0200143 CHECK_STARTUP_PROGRESS(variax->startup_progress,
144 VARIAX_STARTUP_ACTIVATE);
Markus Grabner1027f472010-08-12 01:35:30 +0200145
146 /* activate device: */
147 variax_activate_async(variax, 1);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200148 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
149 variax_startup5, (unsigned long)variax);
Markus Grabner1027f472010-08-12 01:35:30 +0200150}
151
152static void variax_startup5(unsigned long data)
153{
154 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700155
Markus Grabnere1a164d2010-08-23 01:08:25 +0200156 CHECK_STARTUP_PROGRESS(variax->startup_progress,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200157 VARIAX_STARTUP_WORKQUEUE);
Markus Grabner1027f472010-08-12 01:35:30 +0200158
159 /* schedule work for global work queue: */
160 schedule_work(&variax->startup_work);
161}
162
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100163static void variax_startup6(struct work_struct *work)
Markus Grabner1027f472010-08-12 01:35:30 +0200164{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200165 struct usb_line6_variax *variax =
166 container_of(work, struct usb_line6_variax, startup_work);
Markus Grabner1027f472010-08-12 01:35:30 +0200167
Markus Grabnere1a164d2010-08-23 01:08:25 +0200168 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
Markus Grabner1027f472010-08-12 01:35:30 +0200169
170 /* ALSA audio interface: */
Takashi Iwai85a93392015-01-19 15:54:00 +0100171 snd_card_register(variax->line6.card);
Markus Grabner705ecec2009-02-27 19:43:04 -0800172}
173
174/*
175 Process a completely received message.
176*/
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800177static void line6_variax_process_message(struct usb_line6 *line6)
Markus Grabner705ecec2009-02-27 19:43:04 -0800178{
Chris Rorvick1cad3e82015-01-12 12:42:57 -0800179 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800180 const unsigned char *buf = variax->line6.buffer_message;
181
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800182 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800183 case LINE6_RESET:
184 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800185 break;
186
187 case LINE6_SYSEX_BEGIN:
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100188 if (memcmp(buf + 1, variax_init_version + 1,
189 sizeof(variax_init_version) - 1) == 0) {
Markus Grabner1027f472010-08-12 01:35:30 +0200190 variax_startup3(variax);
191 } else if (memcmp(buf + 1, variax_init_done + 1,
192 sizeof(variax_init_done) - 1) == 0) {
193 /* notify of complete initialization: */
194 variax_startup4((unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800195 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800196 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800197 }
198}
199
Markus Grabner705ecec2009-02-27 19:43:04 -0800200/*
201 Variax destructor.
202*/
Takashi Iwaif66fd992015-01-25 18:22:58 +0100203static void line6_variax_disconnect(struct usb_line6 *line6)
Markus Grabner705ecec2009-02-27 19:43:04 -0800204{
Takashi Iwaif66fd992015-01-25 18:22:58 +0100205 struct usb_line6_variax *variax = (struct usb_line6_variax *)line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800206
Markus Grabnere1a164d2010-08-23 01:08:25 +0200207 del_timer(&variax->startup_timer1);
208 del_timer(&variax->startup_timer2);
209 cancel_work_sync(&variax->startup_work);
210
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800211 kfree(variax->buffer_activate);
Markus Grabner705ecec2009-02-27 19:43:04 -0800212}
213
214/*
Markus Grabner1027f472010-08-12 01:35:30 +0200215 Try to init workbench device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800216*/
Takashi Iwaif66fd992015-01-25 18:22:58 +0100217static int variax_init(struct usb_line6 *line6,
218 const struct usb_device_id *id)
Markus Grabner705ecec2009-02-27 19:43:04 -0800219{
Chris Rorvicka221dd42015-01-12 12:42:56 -0800220 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800221 int err;
222
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800223 line6->process_message = line6_variax_process_message;
Chris Rorvicka46c4672015-01-12 12:42:59 -0800224 line6->disconnect = line6_variax_disconnect;
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800225
Markus Grabnere1a164d2010-08-23 01:08:25 +0200226 init_timer(&variax->startup_timer1);
227 init_timer(&variax->startup_timer2);
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100228 INIT_WORK(&variax->startup_work, variax_startup6);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200229
Markus Grabner705ecec2009-02-27 19:43:04 -0800230 /* initialize USB buffers: */
Julia Lawall94002c02010-05-15 23:21:43 +0200231 variax->buffer_activate = kmemdup(variax_activate,
232 sizeof(variax_activate), GFP_KERNEL);
Markus Grabner705ecec2009-02-27 19:43:04 -0800233
Takashi Iwaia019f5e2015-01-19 15:05:10 +0100234 if (variax->buffer_activate == NULL)
Markus Grabner705ecec2009-02-27 19:43:04 -0800235 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800236
Markus Grabner705ecec2009-02-27 19:43:04 -0800237 /* initialize MIDI subsystem: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800238 err = line6_init_midi(&variax->line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700239 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800240 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800241
Markus Grabner1027f472010-08-12 01:35:30 +0200242 /* initiate startup procedure: */
243 variax_startup1(variax);
244 return 0;
245}
246
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100247#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
248#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
249
250/* table of devices that work with this driver */
251static const struct usb_device_id variax_id_table[] = {
252 { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
253 { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
254 {}
255};
256
257MODULE_DEVICE_TABLE(usb, variax_id_table);
258
259static const struct line6_properties variax_properties_table[] = {
260 [LINE6_PODXTLIVE_VARIAX] = {
261 .id = "PODxtLive",
262 .name = "PODxt Live",
263 .capabilities = LINE6_CAP_CONTROL
264 | LINE6_CAP_PCM
265 | LINE6_CAP_HWMON,
266 .altsetting = 1,
267 .ep_ctrl_r = 0x86,
268 .ep_ctrl_w = 0x05,
269 .ep_audio_r = 0x82,
270 .ep_audio_w = 0x01,
271 },
272 [LINE6_VARIAX] = {
273 .id = "Variax",
274 .name = "Variax Workbench",
275 .capabilities = LINE6_CAP_CONTROL,
276 .altsetting = 1,
277 .ep_ctrl_r = 0x82,
278 .ep_ctrl_w = 0x01,
279 /* no audio channel */
280 }
281};
282
283/*
284 Probe USB device.
285*/
286static int variax_probe(struct usb_interface *interface,
287 const struct usb_device_id *id)
288{
Takashi Iwaiaca514b2015-01-25 18:36:29 +0100289 return line6_probe(interface, id,
Takashi Iwai85a93392015-01-19 15:54:00 +0100290 &variax_properties_table[id->driver_info],
Takashi Iwaiaca514b2015-01-25 18:36:29 +0100291 variax_init, sizeof(struct usb_line6_variax));
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100292}
293
294static struct usb_driver variax_driver = {
295 .name = KBUILD_MODNAME,
296 .probe = variax_probe,
297 .disconnect = line6_disconnect,
298#ifdef CONFIG_PM
299 .suspend = line6_suspend,
300 .resume = line6_resume,
301 .reset_resume = line6_resume,
302#endif
303 .id_table = variax_id_table,
304};
305
306module_usb_driver(variax_driver);
307
308MODULE_DESCRIPTION("Vairax Workbench USB driver");
309MODULE_LICENSE("GPL");