1
2
3
4
5
6
7
8
9
10
11
12#include <linux/slab.h>
13#include <linux/wait.h>
14#include <sound/control.h>
15
16#include "audio.h"
17#include "capture.h"
18#include "driver.h"
19#include "playback.h"
20#include "pod.h"
21
22#define POD_SYSEX_CODE 3
23#define POD_BYTES_PER_FRAME 6
24
25
26
27enum {
28 POD_SYSEX_SAVE = 0x24,
29 POD_SYSEX_SYSTEM = 0x56,
30 POD_SYSEX_SYSTEMREQ = 0x57,
31
32 POD_SYSEX_STORE = 0x71,
33 POD_SYSEX_FINISH = 0x72,
34 POD_SYSEX_DUMPMEM = 0x73,
35 POD_SYSEX_DUMP = 0x74,
36 POD_SYSEX_DUMPREQ = 0x75
37
38
39
40};
41
42enum {
43 POD_MONITOR_LEVEL = 0x04,
44 POD_SYSTEM_INVALID = 0x10000
45};
46
47
48
49enum {
50 POD_DUMP_MEMORY = 2
51};
52
53enum {
54 POD_BUSY_READ,
55 POD_BUSY_WRITE,
56 POD_CHANNEL_DIRTY,
57 POD_SAVE_PRESSED,
58 POD_BUSY_MIDISEND
59};
60
61static struct snd_ratden pod_ratden = {
62 .num_min = 78125,
63 .num_max = 78125,
64 .num_step = 1,
65 .den = 2
66};
67
68static struct line6_pcm_properties pod_pcm_properties = {
69 .snd_line6_playback_hw = {
70 .info = (SNDRV_PCM_INFO_MMAP |
71 SNDRV_PCM_INFO_INTERLEAVED |
72 SNDRV_PCM_INFO_BLOCK_TRANSFER |
73 SNDRV_PCM_INFO_MMAP_VALID |
74 SNDRV_PCM_INFO_PAUSE |
75#ifdef CONFIG_PM
76 SNDRV_PCM_INFO_RESUME |
77#endif
78 SNDRV_PCM_INFO_SYNC_START),
79 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
80 .rates = SNDRV_PCM_RATE_KNOT,
81 .rate_min = 39062,
82 .rate_max = 39063,
83 .channels_min = 2,
84 .channels_max = 2,
85 .buffer_bytes_max = 60000,
86 .period_bytes_min = 64,
87 .period_bytes_max = 8192,
88 .periods_min = 1,
89 .periods_max = 1024},
90 .snd_line6_capture_hw = {
91 .info = (SNDRV_PCM_INFO_MMAP |
92 SNDRV_PCM_INFO_INTERLEAVED |
93 SNDRV_PCM_INFO_BLOCK_TRANSFER |
94 SNDRV_PCM_INFO_MMAP_VALID |
95#ifdef CONFIG_PM
96 SNDRV_PCM_INFO_RESUME |
97#endif
98 SNDRV_PCM_INFO_SYNC_START),
99 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
100 .rates = SNDRV_PCM_RATE_KNOT,
101 .rate_min = 39062,
102 .rate_max = 39063,
103 .channels_min = 2,
104 .channels_max = 2,
105 .buffer_bytes_max = 60000,
106 .period_bytes_min = 64,
107 .period_bytes_max = 8192,
108 .periods_min = 1,
109 .periods_max = 1024},
110 .snd_line6_rates = {
111 .nrats = 1,
112 .rats = &pod_ratden},
113 .bytes_per_frame = POD_BYTES_PER_FRAME
114};
115
116static const char pod_version_header[] = {
117 0xf2, 0x7e, 0x7f, 0x06, 0x02
118};
119
120
121static void pod_startup2(unsigned long data);
122static void pod_startup3(struct usb_line6_pod *pod);
123
124static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
125 int size)
126{
127 return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
128 size);
129}
130
131
132
133
134void line6_pod_process_message(struct usb_line6_pod *pod)
135{
136 const unsigned char *buf = pod->line6.buffer_message;
137
138 if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
139 pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
140 pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
141 (int) buf[10];
142 pod_startup3(pod);
143 return;
144 }
145
146
147 if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
148 buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
149 return;
150 }
151 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
152 return;
153
154 if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
155 short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
156 ((int)buf[9] << 4) | (int)buf[10];
157 pod->monitor_level = value;
158 }
159}
160
161
162
163
164void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
165 u8 value)
166{
167 line6_transmit_parameter(&pod->line6, param, value);
168}
169
170
171
172
173static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
174 int code)
175{
176 char *sysex;
177 static const int size = 5;
178
179 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
180 if (!sysex)
181 return -ENOMEM;
182 sysex[SYSEX_DATA_OFS] = code;
183 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
184 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
185 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
186 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
187 line6_send_sysex_message(&pod->line6, sysex, size);
188 kfree(sysex);
189 return 0;
190}
191
192
193
194
195static ssize_t pod_get_serial_number(struct device *dev,
196 struct device_attribute *attr, char *buf)
197{
198 struct usb_interface *interface = to_usb_interface(dev);
199 struct usb_line6_pod *pod = usb_get_intfdata(interface);
200 return sprintf(buf, "%d\n", pod->serial_number);
201}
202
203
204
205
206static ssize_t pod_get_firmware_version(struct device *dev,
207 struct device_attribute *attr,
208 char *buf)
209{
210 struct usb_interface *interface = to_usb_interface(dev);
211 struct usb_line6_pod *pod = usb_get_intfdata(interface);
212 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
213 pod->firmware_version % 100);
214}
215
216
217
218
219static ssize_t pod_get_device_id(struct device *dev,
220 struct device_attribute *attr, char *buf)
221{
222 struct usb_interface *interface = to_usb_interface(dev);
223 struct usb_line6_pod *pod = usb_get_intfdata(interface);
224 return sprintf(buf, "%d\n", pod->device_id);
225}
226
227
228
229
230
231
232
233
234static void pod_startup1(struct usb_line6_pod *pod)
235{
236 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
237
238
239 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
240 (unsigned long)pod);
241}
242
243static void pod_startup2(unsigned long data)
244{
245 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
246 struct usb_line6 *line6 = &pod->line6;
247 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
248
249
250 line6_version_request_async(line6);
251}
252
253static void pod_startup3(struct usb_line6_pod *pod)
254{
255 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
256
257
258 schedule_work(&pod->startup_work);
259}
260
261static void pod_startup4(struct work_struct *work)
262{
263 struct usb_line6_pod *pod =
264 container_of(work, struct usb_line6_pod, startup_work);
265 struct usb_line6 *line6 = &pod->line6;
266
267 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
268
269
270 line6_read_serial_number(&pod->line6, &pod->serial_number);
271
272
273 line6_register_audio(line6);
274}
275
276
277static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
278static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
279 line6_nop_write);
280static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
281 line6_nop_write);
282
283
284static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
285 struct snd_ctl_elem_info *uinfo)
286{
287 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
288 uinfo->count = 1;
289 uinfo->value.integer.min = 0;
290 uinfo->value.integer.max = 65535;
291 return 0;
292}
293
294
295static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
296 struct snd_ctl_elem_value *ucontrol)
297{
298 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
299 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
300 ucontrol->value.integer.value[0] = pod->monitor_level;
301 return 0;
302}
303
304
305static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
306 struct snd_ctl_elem_value *ucontrol)
307{
308 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
309 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
310
311 if (ucontrol->value.integer.value[0] == pod->monitor_level)
312 return 0;
313
314 pod->monitor_level = ucontrol->value.integer.value[0];
315 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
316 POD_MONITOR_LEVEL);
317 return 1;
318}
319
320
321static struct snd_kcontrol_new pod_control_monitor = {
322 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
323 .name = "Monitor Playback Volume",
324 .index = 0,
325 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
326 .info = snd_pod_control_monitor_info,
327 .get = snd_pod_control_monitor_get,
328 .put = snd_pod_control_monitor_put
329};
330
331
332
333
334static void pod_destruct(struct usb_interface *interface)
335{
336 struct usb_line6_pod *pod = usb_get_intfdata(interface);
337
338 if (pod == NULL)
339 return;
340 line6_cleanup_audio(&pod->line6);
341
342 del_timer(&pod->startup_timer);
343 cancel_work_sync(&pod->startup_work);
344}
345
346
347
348
349static int pod_create_files2(struct device *dev)
350{
351 int err;
352
353 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
354 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
355 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
356 return 0;
357}
358
359
360
361
362static int pod_try_init(struct usb_interface *interface,
363 struct usb_line6_pod *pod)
364{
365 int err;
366 struct usb_line6 *line6 = &pod->line6;
367
368 init_timer(&pod->startup_timer);
369 INIT_WORK(&pod->startup_work, pod_startup4);
370
371 if ((interface == NULL) || (pod == NULL))
372 return -ENODEV;
373
374
375 err = pod_create_files2(&interface->dev);
376 if (err < 0)
377 return err;
378
379
380 err = line6_init_audio(line6);
381 if (err < 0)
382 return err;
383
384
385 err = line6_init_midi(line6);
386 if (err < 0)
387 return err;
388
389
390 err = line6_init_pcm(line6, &pod_pcm_properties);
391 if (err < 0)
392 return err;
393
394
395 err = snd_ctl_add(line6->card,
396 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
397 if (err < 0)
398 return err;
399
400
401
402
403
404
405
406 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
407 pod->monitor_level = POD_SYSTEM_INVALID;
408
409
410 pod_startup1(pod);
411 }
412
413 return 0;
414}
415
416
417
418
419int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
420{
421 int err = pod_try_init(interface, pod);
422
423 if (err < 0)
424 pod_destruct(interface);
425
426 return err;
427}
428
429
430
431
432void line6_pod_disconnect(struct usb_interface *interface)
433{
434 struct usb_line6_pod *pod;
435
436 if (interface == NULL)
437 return;
438 pod = usb_get_intfdata(interface);
439
440 if (pod != NULL) {
441 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
442 struct device *dev = &interface->dev;
443
444 if (line6pcm != NULL)
445 line6_pcm_disconnect(line6pcm);
446
447 if (dev != NULL) {
448
449 device_remove_file(dev, &dev_attr_device_id);
450 device_remove_file(dev, &dev_attr_firmware_version);
451 device_remove_file(dev, &dev_attr_serial_number);
452 }
453 }
454
455 pod_destruct(interface);
456}
457