Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/line6/variax.c
26426 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Line 6 Linux USB driver
4
*
5
* Copyright (C) 2004-2010 Markus Grabner ([email protected])
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
Stages of Variax startup procedure
23
*/
24
enum {
25
VARIAX_STARTUP_VERSIONREQ,
26
VARIAX_STARTUP_ACTIVATE,
27
VARIAX_STARTUP_SETUP,
28
};
29
30
enum {
31
LINE6_PODXTLIVE_VARIAX,
32
LINE6_VARIAX
33
};
34
35
struct usb_line6_variax {
36
/* Generic Line 6 USB data */
37
struct usb_line6 line6;
38
39
/* Buffer for activation code */
40
unsigned char *buffer_activate;
41
42
/* Current progress in startup procedure */
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
This message is sent by the device during initialization and identifies
52
the connected guitar version.
53
*/
54
static const char variax_init_version[] = {
55
0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
56
0x07, 0x00, 0x00, 0x00
57
};
58
59
/*
60
This message is the last one sent by the device during initialization.
61
*/
62
static const char variax_init_done[] = {
63
0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
64
};
65
66
static const char variax_activate[] = {
67
0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
68
0xf7
69
};
70
71
static 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
Variax startup procedure.
80
This is a sequence of functions with special requirements (e.g., must
81
not run immediately after initialization, must not run in interrupt
82
context). After the last one has finished, the device is ready to use.
83
*/
84
85
static 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
/* repeat request until getting the response */
92
schedule_delayed_work(&line6->startup_work,
93
msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
94
/* request firmware version: */
95
line6_version_request_async(line6);
96
break;
97
case VARIAX_STARTUP_ACTIVATE:
98
/* activate device: */
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
/* ALSA audio interface: */
106
snd_card_register(variax->line6.card);
107
break;
108
}
109
}
110
111
/*
112
Process a completely received message.
113
*/
114
static 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
/* notify of complete initialization: */
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
Variax destructor.
147
*/
148
static 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
Try to init workbench device.
157
*/
158
static 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
/* initialize USB buffers: */
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
/* initiate startup procedure: */
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
/* table of devices that work with this driver */
184
static 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
190
MODULE_DEVICE_TABLE(usb, variax_id_table);
191
192
static 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
/* no audio channel */
213
}
214
};
215
216
/*
217
Probe USB device.
218
*/
219
static 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
227
static 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
239
module_usb_driver(variax_driver);
240
241
MODULE_DESCRIPTION("Variax Workbench USB driver");
242
MODULE_LICENSE("GPL");
243
244