staging: line6: clean up line6_pod_process_message()
[deliverable/linux.git] / drivers / staging / line6 / pod.c
1 /*
2 * Line6 Linux USB driver - 0.9.1beta
3 *
4 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
5 *
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
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 /* 24bit audio (stereo) */
24
25 /* *INDENT-OFF* */
26
27 enum {
28 POD_SYSEX_SAVE = 0x24,
29 POD_SYSEX_SYSTEM = 0x56,
30 POD_SYSEX_SYSTEMREQ = 0x57,
31 /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
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 /* dumps entire internal memory of PODxt Pro */
39 /* POD_SYSEX_DUMPMEM2 = 0x76 */
40 };
41
42 enum {
43 POD_MONITOR_LEVEL = 0x04,
44 POD_SYSTEM_INVALID = 0x10000
45 };
46
47 /* *INDENT-ON* */
48
49 enum {
50 POD_DUMP_MEMORY = 2
51 };
52
53 enum {
54 POD_BUSY_READ,
55 POD_BUSY_WRITE,
56 POD_CHANNEL_DIRTY,
57 POD_SAVE_PRESSED,
58 POD_BUSY_MIDISEND
59 };
60
61 static struct snd_ratden pod_ratden = {
62 .num_min = 78125,
63 .num_max = 78125,
64 .num_step = 1,
65 .den = 2
66 };
67
68 static 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
116 static const char pod_version_header[] = {
117 0xf2, 0x7e, 0x7f, 0x06, 0x02
118 };
119
120 /* forward declarations: */
121 static void pod_startup2(unsigned long data);
122 static void pod_startup3(struct usb_line6_pod *pod);
123
124 static 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 Process a completely received message.
133 */
134 void 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 /* Only look for sysex messages from this device */
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
155 if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
156 short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
157 ((int)buf[9] << 4) | (int)buf[10];
158 pod->monitor_level = value;
159 }
160 }
161
162 /*
163 Transmit PODxt Pro control parameter.
164 */
165 void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
166 u8 value)
167 {
168 line6_transmit_parameter(&pod->line6, param, value);
169 }
170
171 /*
172 Send system parameter (from integer).
173 */
174 static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
175 int code)
176 {
177 char *sysex;
178 static const int size = 5;
179
180 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
181 if (!sysex)
182 return -ENOMEM;
183 sysex[SYSEX_DATA_OFS] = code;
184 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
185 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
186 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
187 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
188 line6_send_sysex_message(&pod->line6, sysex, size);
189 kfree(sysex);
190 return 0;
191 }
192
193 /*
194 "read" request on "serial_number" special file.
195 */
196 static ssize_t pod_get_serial_number(struct device *dev,
197 struct device_attribute *attr, char *buf)
198 {
199 struct usb_interface *interface = to_usb_interface(dev);
200 struct usb_line6_pod *pod = usb_get_intfdata(interface);
201 return sprintf(buf, "%d\n", pod->serial_number);
202 }
203
204 /*
205 "read" request on "firmware_version" special file.
206 */
207 static ssize_t pod_get_firmware_version(struct device *dev,
208 struct device_attribute *attr,
209 char *buf)
210 {
211 struct usb_interface *interface = to_usb_interface(dev);
212 struct usb_line6_pod *pod = usb_get_intfdata(interface);
213 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
214 pod->firmware_version % 100);
215 }
216
217 /*
218 "read" request on "device_id" special file.
219 */
220 static ssize_t pod_get_device_id(struct device *dev,
221 struct device_attribute *attr, char *buf)
222 {
223 struct usb_interface *interface = to_usb_interface(dev);
224 struct usb_line6_pod *pod = usb_get_intfdata(interface);
225 return sprintf(buf, "%d\n", pod->device_id);
226 }
227
228 /*
229 POD startup procedure.
230 This is a sequence of functions with special requirements (e.g., must
231 not run immediately after initialization, must not run in interrupt
232 context). After the last one has finished, the device is ready to use.
233 */
234
235 static void pod_startup1(struct usb_line6_pod *pod)
236 {
237 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
238
239 /* delay startup procedure: */
240 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
241 (unsigned long)pod);
242 }
243
244 static void pod_startup2(unsigned long data)
245 {
246 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
247 struct usb_line6 *line6 = &pod->line6;
248 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
249
250 /* request firmware version: */
251 line6_version_request_async(line6);
252 }
253
254 static void pod_startup3(struct usb_line6_pod *pod)
255 {
256 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
257
258 /* schedule work for global work queue: */
259 schedule_work(&pod->startup_work);
260 }
261
262 static void pod_startup4(struct work_struct *work)
263 {
264 struct usb_line6_pod *pod =
265 container_of(work, struct usb_line6_pod, startup_work);
266 struct usb_line6 *line6 = &pod->line6;
267
268 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
269
270 /* serial number: */
271 line6_read_serial_number(&pod->line6, &pod->serial_number);
272
273 /* ALSA audio interface: */
274 line6_register_audio(line6);
275 }
276
277 /* POD special files: */
278 static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
279 static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
280 line6_nop_write);
281 static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
282 line6_nop_write);
283
284 /* control info callback */
285 static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
286 struct snd_ctl_elem_info *uinfo)
287 {
288 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
289 uinfo->count = 1;
290 uinfo->value.integer.min = 0;
291 uinfo->value.integer.max = 65535;
292 return 0;
293 }
294
295 /* control get callback */
296 static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
297 struct snd_ctl_elem_value *ucontrol)
298 {
299 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
300 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
301 ucontrol->value.integer.value[0] = pod->monitor_level;
302 return 0;
303 }
304
305 /* control put callback */
306 static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
307 struct snd_ctl_elem_value *ucontrol)
308 {
309 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
310 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
311
312 if (ucontrol->value.integer.value[0] == pod->monitor_level)
313 return 0;
314
315 pod->monitor_level = ucontrol->value.integer.value[0];
316 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
317 POD_MONITOR_LEVEL);
318 return 1;
319 }
320
321 /* control definition */
322 static struct snd_kcontrol_new pod_control_monitor = {
323 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
324 .name = "Monitor Playback Volume",
325 .index = 0,
326 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
327 .info = snd_pod_control_monitor_info,
328 .get = snd_pod_control_monitor_get,
329 .put = snd_pod_control_monitor_put
330 };
331
332 /*
333 POD destructor.
334 */
335 static void pod_destruct(struct usb_interface *interface)
336 {
337 struct usb_line6_pod *pod = usb_get_intfdata(interface);
338
339 if (pod == NULL)
340 return;
341 line6_cleanup_audio(&pod->line6);
342
343 del_timer(&pod->startup_timer);
344 cancel_work_sync(&pod->startup_work);
345 }
346
347 /*
348 Create sysfs entries.
349 */
350 static int pod_create_files2(struct device *dev)
351 {
352 int err;
353
354 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
355 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
356 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
357 return 0;
358 }
359
360 /*
361 Try to init POD device.
362 */
363 static int pod_try_init(struct usb_interface *interface,
364 struct usb_line6_pod *pod)
365 {
366 int err;
367 struct usb_line6 *line6 = &pod->line6;
368
369 init_timer(&pod->startup_timer);
370 INIT_WORK(&pod->startup_work, pod_startup4);
371
372 if ((interface == NULL) || (pod == NULL))
373 return -ENODEV;
374
375 /* create sysfs entries: */
376 err = pod_create_files2(&interface->dev);
377 if (err < 0)
378 return err;
379
380 /* initialize audio system: */
381 err = line6_init_audio(line6);
382 if (err < 0)
383 return err;
384
385 /* initialize MIDI subsystem: */
386 err = line6_init_midi(line6);
387 if (err < 0)
388 return err;
389
390 /* initialize PCM subsystem: */
391 err = line6_init_pcm(line6, &pod_pcm_properties);
392 if (err < 0)
393 return err;
394
395 /* register monitor control: */
396 err = snd_ctl_add(line6->card,
397 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
398 if (err < 0)
399 return err;
400
401 /*
402 When the sound card is registered at this point, the PODxt Live
403 displays "Invalid Code Error 07", so we do it later in the event
404 handler.
405 */
406
407 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
408 pod->monitor_level = POD_SYSTEM_INVALID;
409
410 /* initiate startup procedure: */
411 pod_startup1(pod);
412 }
413
414 return 0;
415 }
416
417 /*
418 Init POD device (and clean up in case of failure).
419 */
420 int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
421 {
422 int err = pod_try_init(interface, pod);
423
424 if (err < 0)
425 pod_destruct(interface);
426
427 return err;
428 }
429
430 /*
431 POD device disconnected.
432 */
433 void line6_pod_disconnect(struct usb_interface *interface)
434 {
435 struct usb_line6_pod *pod;
436
437 if (interface == NULL)
438 return;
439 pod = usb_get_intfdata(interface);
440
441 if (pod != NULL) {
442 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
443 struct device *dev = &interface->dev;
444
445 if (line6pcm != NULL)
446 line6_pcm_disconnect(line6pcm);
447
448 if (dev != NULL) {
449 /* remove sysfs entries: */
450 device_remove_file(dev, &dev_attr_device_id);
451 device_remove_file(dev, &dev_attr_firmware_version);
452 device_remove_file(dev, &dev_attr_serial_number);
453 }
454 }
455
456 pod_destruct(interface);
457 }
This page took 0.050938 seconds and 5 git commands to generate.