blob: a591c2c5794f2cf34c89a7775c01235d12f7e105 [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 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 {
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};
Markus Grabner705ecec2009-02-27 19:43:04 -080071
Markus Grabner705ecec2009-02-27 19:43:04 -080072#define VARIAX_OFFSET_ACTIVATE 7
73
Markus Grabner1027f472010-08-12 01:35:30 +020074/*
75 This message is sent by the device during initialization and identifies
Markus Grabner1027f472010-08-12 01:35:30 +020076 the connected guitar version.
77*/
78static 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*/
86static const char variax_init_done[] = {
87 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
88};
89
Markus Grabner705ecec2009-02-27 19:43:04 -080090static const char variax_activate[] = {
91 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
92 0xf7
93};
Markus Grabner1027f472010-08-12 01:35:30 +020094
Markus Grabner1027f472010-08-12 01:35:30 +020095/* forward declarations: */
Markus Grabner1027f472010-08-12 01:35:30 +020096static void variax_startup2(unsigned long data);
97static void variax_startup4(unsigned long data);
98static void variax_startup5(unsigned long data);
99
Markus Grabner1027f472010-08-12 01:35:30 +0200100static void variax_activate_async(struct usb_line6_variax *variax, int a)
Markus Grabner705ecec2009-02-27 19:43:04 -0800101{
Markus Grabner1027f472010-08-12 01:35:30 +0200102 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800103 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
104 sizeof(variax_activate));
Markus Grabner705ecec2009-02-27 19:43:04 -0800105}
106
107/*
Markus Grabner1027f472010-08-12 01:35:30 +0200108 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.
Markus Grabner705ecec2009-02-27 19:43:04 -0800112*/
Markus Grabner1027f472010-08-12 01:35:30 +0200113
114static void variax_startup1(struct usb_line6_variax *variax)
Markus Grabner705ecec2009-02-27 19:43:04 -0800115{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200116 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200117
118 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200119 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
120 variax_startup2, (unsigned long)variax);
Markus Grabner705ecec2009-02-27 19:43:04 -0800121}
122
Markus Grabner1027f472010-08-12 01:35:30 +0200123static void variax_startup2(unsigned long data)
Markus Grabner705ecec2009-02-27 19:43:04 -0800124{
Markus Grabner1027f472010-08-12 01:35:30 +0200125 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
126 struct usb_line6 *line6 = &variax->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200127
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);
Markus Grabner705ecec2009-02-27 19:43:04 -0800135
Markus Grabner1027f472010-08-12 01:35:30 +0200136 /* request firmware version: */
137 line6_version_request_async(line6);
138}
Markus Grabner705ecec2009-02-27 19:43:04 -0800139
Markus Grabner1027f472010-08-12 01:35:30 +0200140static void variax_startup3(struct usb_line6_variax *variax)
141{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200142 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200143
144 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200145 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
146 variax_startup4, (unsigned long)variax);
Markus Grabner1027f472010-08-12 01:35:30 +0200147}
148
149static void variax_startup4(unsigned long data)
150{
151 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700152
Markus Grabnere1a164d2010-08-23 01:08:25 +0200153 CHECK_STARTUP_PROGRESS(variax->startup_progress,
154 VARIAX_STARTUP_ACTIVATE);
Markus Grabner1027f472010-08-12 01:35:30 +0200155
156 /* activate device: */
157 variax_activate_async(variax, 1);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200158 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
159 variax_startup5, (unsigned long)variax);
Markus Grabner1027f472010-08-12 01:35:30 +0200160}
161
162static void variax_startup5(unsigned long data)
163{
164 struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700165
Markus Grabnere1a164d2010-08-23 01:08:25 +0200166 CHECK_STARTUP_PROGRESS(variax->startup_progress,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200167 VARIAX_STARTUP_WORKQUEUE);
Markus Grabner1027f472010-08-12 01:35:30 +0200168
169 /* schedule work for global work queue: */
170 schedule_work(&variax->startup_work);
171}
172
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100173static void variax_startup6(struct work_struct *work)
Markus Grabner1027f472010-08-12 01:35:30 +0200174{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200175 struct usb_line6_variax *variax =
176 container_of(work, struct usb_line6_variax, startup_work);
Markus Grabner1027f472010-08-12 01:35:30 +0200177
Markus Grabnere1a164d2010-08-23 01:08:25 +0200178 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
Markus Grabner1027f472010-08-12 01:35:30 +0200179
180 /* ALSA audio interface: */
Takashi Iwai85a93392015-01-19 15:54:00 +0100181 snd_card_register(variax->line6.card);
Markus Grabner705ecec2009-02-27 19:43:04 -0800182}
183
184/*
185 Process a completely received message.
186*/
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800187static void line6_variax_process_message(struct usb_line6 *line6)
Markus Grabner705ecec2009-02-27 19:43:04 -0800188{
Chris Rorvick1cad3e82015-01-12 12:42:57 -0800189 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800190 const unsigned char *buf = variax->line6.buffer_message;
191
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800192 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800193 case LINE6_RESET:
194 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800195 break;
196
197 case LINE6_SYSEX_BEGIN:
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100198 if (memcmp(buf + 1, variax_init_version + 1,
199 sizeof(variax_init_version) - 1) == 0) {
Markus Grabner1027f472010-08-12 01:35:30 +0200200 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);
Markus Grabner705ecec2009-02-27 19:43:04 -0800205 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800206 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800207 }
208}
209
Markus Grabner705ecec2009-02-27 19:43:04 -0800210/*
211 Variax destructor.
212*/
Takashi Iwai85a93392015-01-19 15:54:00 +0100213static void line6_variax_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -0800214{
Takashi Iwai85a93392015-01-19 15:54:00 +0100215 struct usb_line6_variax *variax;
Markus Grabner705ecec2009-02-27 19:43:04 -0800216
Takashi Iwai85a93392015-01-19 15:54:00 +0100217 if (!interface)
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800218 return;
Takashi Iwai85a93392015-01-19 15:54:00 +0100219
220 variax = usb_get_intfdata(interface);
221 if (!variax)
222 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800223
Markus Grabnere1a164d2010-08-23 01:08:25 +0200224 del_timer(&variax->startup_timer1);
225 del_timer(&variax->startup_timer2);
226 cancel_work_sync(&variax->startup_work);
227
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800228 kfree(variax->buffer_activate);
Markus Grabner705ecec2009-02-27 19:43:04 -0800229}
230
231/*
Markus Grabner1027f472010-08-12 01:35:30 +0200232 Try to init workbench device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800233*/
Takashi Iwai85a93392015-01-19 15:54:00 +0100234static int variax_init(struct usb_interface *interface,
235 struct usb_line6 *line6)
Markus Grabner705ecec2009-02-27 19:43:04 -0800236{
Chris Rorvicka221dd42015-01-12 12:42:56 -0800237 struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800238 int err;
239
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800240 line6->process_message = line6_variax_process_message;
Chris Rorvicka46c4672015-01-12 12:42:59 -0800241 line6->disconnect = line6_variax_disconnect;
Chris Rorvick01f6b2b2015-01-12 12:42:58 -0800242
Markus Grabnere1a164d2010-08-23 01:08:25 +0200243 init_timer(&variax->startup_timer1);
244 init_timer(&variax->startup_timer2);
Stefan Hajnoczi323246b2012-11-22 20:49:23 +0100245 INIT_WORK(&variax->startup_work, variax_startup6);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200246
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800247 if ((interface == NULL) || (variax == NULL))
248 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800249
250 /* initialize USB buffers: */
Julia Lawall94002c02010-05-15 23:21:43 +0200251 variax->buffer_activate = kmemdup(variax_activate,
252 sizeof(variax_activate), GFP_KERNEL);
Markus Grabner705ecec2009-02-27 19:43:04 -0800253
Takashi Iwaia019f5e2015-01-19 15:05:10 +0100254 if (variax->buffer_activate == NULL)
Markus Grabner705ecec2009-02-27 19:43:04 -0800255 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800256
Markus Grabner705ecec2009-02-27 19:43:04 -0800257 /* initialize MIDI subsystem: */
Greg Kroah-Hartman9cd57f72009-02-27 22:43:57 -0800258 err = line6_init_midi(&variax->line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700259 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800260 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800261
Markus Grabner1027f472010-08-12 01:35:30 +0200262 /* initiate startup procedure: */
263 variax_startup1(variax);
264 return 0;
265}
266
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100267#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 */
271static 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
277MODULE_DEVICE_TABLE(usb, variax_id_table);
278
279static 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*/
306static int variax_probe(struct usb_interface *interface,
307 const struct usb_device_id *id)
308{
309 struct usb_line6_variax *variax;
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100310
311 variax = kzalloc(sizeof(*variax), GFP_KERNEL);
312 if (!variax)
313 return -ENODEV;
Takashi Iwai85a93392015-01-19 15:54:00 +0100314 return line6_probe(interface, &variax->line6,
315 &variax_properties_table[id->driver_info],
316 variax_init);
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100317}
318
319static 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
331module_usb_driver(variax_driver);
332
333MODULE_DESCRIPTION("Vairax Workbench USB driver");
334MODULE_LICENSE("GPL");