1
2
3
4
5
6
7
8#include <linux/slab.h>
9#include <linux/spinlock.h>
10#include <linux/usb.h>
11#include <linux/wait.h>
12#include <linux/module.h>
13#include <sound/core.h>
14
15#include "driver.h"
16
17#define VARIAX_STARTUP_DELAY1 1000
18#define VARIAX_STARTUP_DELAY3 100
19#define VARIAX_STARTUP_DELAY4 100
20
21
22
23
24enum {
25 VARIAX_STARTUP_VERSIONREQ,
26 VARIAX_STARTUP_ACTIVATE,
27 VARIAX_STARTUP_SETUP,
28};
29
30enum {
31 LINE6_PODXTLIVE_VARIAX,
32 LINE6_VARIAX
33};
34
35struct usb_line6_variax {
36
37 struct usb_line6 line6;
38
39
40 unsigned char *buffer_activate;
41
42
43 int startup_progress;
44};
45
46#define line6_to_variax(x) container_of(x, struct usb_line6_variax, line6)
47
48#define VARIAX_OFFSET_ACTIVATE 7
49
50
51
52
53
54static const char variax_init_version[] = {
55 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
56 0x07, 0x00, 0x00, 0x00
57};
58
59
60
61
62static const char variax_init_done[] = {
63 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
64};
65
66static const char variax_activate[] = {
67 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
68 0xf7
69};
70
71static void variax_activate_async(struct usb_line6_variax *variax, int a)
72{
73 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
74 line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
75 sizeof(variax_activate));
76}
77
78
79
80
81
82
83
84
85static void variax_startup(struct usb_line6 *line6)
86{
87 struct usb_line6_variax *variax = line6_to_variax(line6);
88
89 switch (variax->startup_progress) {
90 case VARIAX_STARTUP_VERSIONREQ:
91
92 schedule_delayed_work(&line6->startup_work,
93 msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
94
95 line6_version_request_async(line6);
96 break;
97 case VARIAX_STARTUP_ACTIVATE:
98
99 variax_activate_async(variax, 1);
100 variax->startup_progress = VARIAX_STARTUP_SETUP;
101 schedule_delayed_work(&line6->startup_work,
102 msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
103 break;
104 case VARIAX_STARTUP_SETUP:
105
106 snd_card_register(variax->line6.card);
107 break;
108 }
109}
110
111
112
113
114static void line6_variax_process_message(struct usb_line6 *line6)
115{
116 struct usb_line6_variax *variax = line6_to_variax(line6);
117 const unsigned char *buf = variax->line6.buffer_message;
118
119 switch (buf[0]) {
120 case LINE6_RESET:
121 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
122 break;
123
124 case LINE6_SYSEX_BEGIN:
125 if (memcmp(buf + 1, variax_init_version + 1,
126 sizeof(variax_init_version) - 1) == 0) {
127 if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
128 break;
129 variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
130 cancel_delayed_work(&line6->startup_work);
131 schedule_delayed_work(&line6->startup_work,
132 msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
133 } else if (memcmp(buf + 1, variax_init_done + 1,
134 sizeof(variax_init_done) - 1) == 0) {
135
136 if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
137 break;
138 cancel_delayed_work(&line6->startup_work);
139 schedule_delayed_work(&line6->startup_work, 0);
140 }
141 break;
142 }
143}
144
145
146
147
148static void line6_variax_disconnect(struct usb_line6 *line6)
149{
150 struct usb_line6_variax *variax = line6_to_variax(line6);
151
152 kfree(variax->buffer_activate);
153}
154
155
156
157
158static int variax_init(struct usb_line6 *line6,
159 const struct usb_device_id *id)
160{
161 struct usb_line6_variax *variax = line6_to_variax(line6);
162
163 line6->process_message = line6_variax_process_message;
164 line6->disconnect = line6_variax_disconnect;
165 line6->startup = variax_startup;
166
167
168 variax->buffer_activate = kmemdup(variax_activate,
169 sizeof(variax_activate), GFP_KERNEL);
170
171 if (variax->buffer_activate == NULL)
172 return -ENOMEM;
173
174
175 schedule_delayed_work(&line6->startup_work,
176 msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
177 return 0;
178}
179
180#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
181#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
182
183
184static const struct usb_device_id variax_id_table[] = {
185 { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
186 { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
187 {}
188};
189
190MODULE_DEVICE_TABLE(usb, variax_id_table);
191
192static const struct line6_properties variax_properties_table[] = {
193 [LINE6_PODXTLIVE_VARIAX] = {
194 .id = "PODxtLive",
195 .name = "PODxt Live",
196 .capabilities = LINE6_CAP_CONTROL
197 | LINE6_CAP_CONTROL_MIDI,
198 .altsetting = 1,
199 .ep_ctrl_r = 0x86,
200 .ep_ctrl_w = 0x05,
201 .ep_audio_r = 0x82,
202 .ep_audio_w = 0x01,
203 },
204 [LINE6_VARIAX] = {
205 .id = "Variax",
206 .name = "Variax Workbench",
207 .capabilities = LINE6_CAP_CONTROL
208 | LINE6_CAP_CONTROL_MIDI,
209 .altsetting = 1,
210 .ep_ctrl_r = 0x82,
211 .ep_ctrl_w = 0x01,
212
213 }
214};
215
216
217
218
219static int variax_probe(struct usb_interface *interface,
220 const struct usb_device_id *id)
221{
222 return line6_probe(interface, id, "Line6-Variax",
223 &variax_properties_table[id->driver_info],
224 variax_init, sizeof(struct usb_line6_variax));
225}
226
227static struct usb_driver variax_driver = {
228 .name = KBUILD_MODNAME,
229 .probe = variax_probe,
230 .disconnect = line6_disconnect,
231#ifdef CONFIG_PM
232 .suspend = line6_suspend,
233 .resume = line6_resume,
234 .reset_resume = line6_resume,
235#endif
236 .id_table = variax_id_table,
237};
238
239module_usb_driver(variax_driver);
240
241MODULE_DESCRIPTION("Variax Workbench USB driver");
242MODULE_LICENSE("GPL");
243