blob: 68727b2dfb8fbd0d5ffa00cac96a81f8282cd143 [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 Grabner1027f4762010-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>
Markus Grabner705ecec2009-02-27 19:43:04 -080013#include <sound/core.h>
14#include <sound/control.h>
15#include <sound/pcm.h>
16#include <sound/pcm_params.h>
17
18#include "audio.h"
19#include "capture.h"
Markus Grabner1027f4762010-08-12 01:35:30 +020020#include "driver.h"
Markus Grabner705ecec2009-02-27 19:43:04 -080021#include "playback.h"
22#include "pod.h"
23
Markus Grabner1027f4762010-08-12 01:35:30 +020024#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
25
Markus Grabnere1a164d2010-08-23 01:08:25 +020026static struct snd_line6_pcm *dev2pcm(struct device *dev)
Markus Grabner1027f4762010-08-12 01:35:30 +020027{
28 struct usb_interface *interface = to_usb_interface(dev);
29 struct usb_line6 *line6 = usb_get_intfdata(interface);
30 struct snd_line6_pcm *line6pcm = line6->line6pcm;
31 return line6pcm;
32}
33
34/*
35 "read" request on "impulse_volume" special file.
36*/
37static ssize_t pcm_get_impulse_volume(struct device *dev,
Markus Grabnere1a164d2010-08-23 01:08:25 +020038 struct device_attribute *attr, char *buf)
Markus Grabner1027f4762010-08-12 01:35:30 +020039{
40 return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
41}
42
43/*
44 "write" request on "impulse_volume" special file.
45*/
46static ssize_t pcm_set_impulse_volume(struct device *dev,
47 struct device_attribute *attr,
48 const char *buf, size_t count)
49{
50 struct snd_line6_pcm *line6pcm = dev2pcm(dev);
51 int value = simple_strtoul(buf, NULL, 10);
52 line6pcm->impulse_volume = value;
53
Markus Grabnere1a164d2010-08-23 01:08:25 +020054 if (value > 0)
Markus Grabner1027f4762010-08-12 01:35:30 +020055 line6_pcm_start(line6pcm, MASK_PCM_IMPULSE);
56 else
57 line6_pcm_stop(line6pcm, MASK_PCM_IMPULSE);
58
59 return count;
60}
61
62/*
63 "read" request on "impulse_period" special file.
64*/
65static ssize_t pcm_get_impulse_period(struct device *dev,
Markus Grabnere1a164d2010-08-23 01:08:25 +020066 struct device_attribute *attr, char *buf)
Markus Grabner1027f4762010-08-12 01:35:30 +020067{
68 return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
69}
70
71/*
72 "write" request on "impulse_period" special file.
73*/
74static ssize_t pcm_set_impulse_period(struct device *dev,
75 struct device_attribute *attr,
76 const char *buf, size_t count)
77{
78 dev2pcm(dev)->impulse_period = simple_strtoul(buf, NULL, 10);
79 return count;
80}
81
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -080082static DEVICE_ATTR(impulse_volume, S_IWUSR | S_IRUGO, pcm_get_impulse_volume,
Markus Grabnere1a164d2010-08-23 01:08:25 +020083 pcm_set_impulse_volume);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -080084static DEVICE_ATTR(impulse_period, S_IWUSR | S_IRUGO, pcm_get_impulse_period,
Markus Grabnere1a164d2010-08-23 01:08:25 +020085 pcm_set_impulse_period);
Markus Grabner1027f4762010-08-12 01:35:30 +020086
87#endif
88
89int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
90{
Markus Grabnere1a164d2010-08-23 01:08:25 +020091 unsigned long flags_old =
92 __sync_fetch_and_or(&line6pcm->flags, channels);
Markus Grabner1027f4762010-08-12 01:35:30 +020093 unsigned long flags_new = flags_old | channels;
94 int err = 0;
95
Markus Grabner1027f4762010-08-12 01:35:30 +020096 line6pcm->prev_fbuf = NULL;
Markus Grabnere1a164d2010-08-23 01:08:25 +020097
Markus Grabner1027f4762010-08-12 01:35:30 +020098 if (((flags_old & MASK_CAPTURE) == 0) &&
99 ((flags_new & MASK_CAPTURE) != 0)) {
100 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +0200101 Waiting for completion of active URBs in the stop handler is
102 a bug, we therefore report an error if capturing is restarted
103 too soon.
104 */
105 if (line6pcm->active_urb_in | line6pcm->unlink_urb_in)
Markus Grabner1027f4762010-08-12 01:35:30 +0200106 return -EBUSY;
107
Markus Grabner1027f4762010-08-12 01:35:30 +0200108 line6pcm->count_in = 0;
109 line6pcm->prev_fsize = 0;
110 err = line6_submit_audio_in_all_urbs(line6pcm);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200111
Markus Grabner1027f4762010-08-12 01:35:30 +0200112 if (err < 0) {
113 __sync_fetch_and_and(&line6pcm->flags, ~channels);
114 return err;
115 }
116 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200117
Markus Grabner1027f4762010-08-12 01:35:30 +0200118 if (((flags_old & MASK_PLAYBACK) == 0) &&
119 ((flags_new & MASK_PLAYBACK) != 0)) {
120 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +0200121 See comment above regarding PCM restart.
122 */
123 if (line6pcm->active_urb_out | line6pcm->unlink_urb_out)
Markus Grabner1027f4762010-08-12 01:35:30 +0200124 return -EBUSY;
125
Markus Grabner1027f4762010-08-12 01:35:30 +0200126 line6pcm->count_out = 0;
127 err = line6_submit_audio_out_all_urbs(line6pcm);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200128
Markus Grabner1027f4762010-08-12 01:35:30 +0200129 if (err < 0) {
130 __sync_fetch_and_and(&line6pcm->flags, ~channels);
131 return err;
132 }
133 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200134
Markus Grabner1027f4762010-08-12 01:35:30 +0200135 return 0;
136}
137
138int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels)
139{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200140 unsigned long flags_old =
141 __sync_fetch_and_and(&line6pcm->flags, ~channels);
Markus Grabner1027f4762010-08-12 01:35:30 +0200142 unsigned long flags_new = flags_old & ~channels;
143
144 if (((flags_old & MASK_CAPTURE) != 0) &&
145 ((flags_new & MASK_CAPTURE) == 0)) {
146 line6_unlink_audio_in_urbs(line6pcm);
Markus Grabner1027f4762010-08-12 01:35:30 +0200147 }
148
149 if (((flags_old & MASK_PLAYBACK) != 0) &&
150 ((flags_new & MASK_PLAYBACK) == 0)) {
151 line6_unlink_audio_out_urbs(line6pcm);
Markus Grabner1027f4762010-08-12 01:35:30 +0200152 }
Markus Grabner1027f4762010-08-12 01:35:30 +0200153
154 return 0;
155}
156
Markus Grabner705ecec2009-02-27 19:43:04 -0800157/* trigger callback */
158int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
159{
160 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
Markus Grabner705ecec2009-02-27 19:43:04 -0800161 struct snd_pcm_substream *s;
162 int err;
163 unsigned long flags;
164
165 spin_lock_irqsave(&line6pcm->lock_trigger, flags);
166 clear_bit(BIT_PREPARED, &line6pcm->flags);
167
Markus Grabner705ecec2009-02-27 19:43:04 -0800168 snd_pcm_group_for_each_entry(s, substream) {
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800169 switch (s->stream) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800170 case SNDRV_PCM_STREAM_PLAYBACK:
Markus Grabner1027f4762010-08-12 01:35:30 +0200171 err = snd_line6_playback_trigger(line6pcm, cmd);
Markus Grabner705ecec2009-02-27 19:43:04 -0800172
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800173 if (err < 0) {
174 spin_unlock_irqrestore(&line6pcm->lock_trigger,
175 flags);
Markus Grabner705ecec2009-02-27 19:43:04 -0800176 return err;
177 }
178
179 break;
180
181 case SNDRV_PCM_STREAM_CAPTURE:
Markus Grabner1027f4762010-08-12 01:35:30 +0200182 err = snd_line6_capture_trigger(line6pcm, cmd);
Markus Grabner705ecec2009-02-27 19:43:04 -0800183
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800184 if (err < 0) {
185 spin_unlock_irqrestore(&line6pcm->lock_trigger,
186 flags);
Markus Grabner705ecec2009-02-27 19:43:04 -0800187 return err;
188 }
189
190 break;
191
192 default:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200193 dev_err(line6pcm->line6->ifcdev,
194 "Unknown stream direction %d\n", s->stream);
Markus Grabner705ecec2009-02-27 19:43:04 -0800195 }
196 }
197
198 spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
199 return 0;
200}
201
202/* control info callback */
Markus Grabner1027f4762010-08-12 01:35:30 +0200203static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
204 struct snd_ctl_elem_info *uinfo)
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800205{
Markus Grabner705ecec2009-02-27 19:43:04 -0800206 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
207 uinfo->count = 2;
208 uinfo->value.integer.min = 0;
209 uinfo->value.integer.max = 256;
210 return 0;
211}
212
213/* control get callback */
Markus Grabner1027f4762010-08-12 01:35:30 +0200214static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
215 struct snd_ctl_elem_value *ucontrol)
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800216{
Markus Grabner705ecec2009-02-27 19:43:04 -0800217 int i;
218 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
219
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800220 for (i = 2; i--;)
Markus Grabner1027f4762010-08-12 01:35:30 +0200221 ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
Markus Grabner705ecec2009-02-27 19:43:04 -0800222
223 return 0;
224}
225
226/* control put callback */
Markus Grabner1027f4762010-08-12 01:35:30 +0200227static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
228 struct snd_ctl_elem_value *ucontrol)
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800229{
Markus Grabner705ecec2009-02-27 19:43:04 -0800230 int i, changed = 0;
231 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
232
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800233 for (i = 2; i--;)
Markus Grabnere1a164d2010-08-23 01:08:25 +0200234 if (line6pcm->volume_playback[i] !=
235 ucontrol->value.integer.value[i]) {
236 line6pcm->volume_playback[i] =
237 ucontrol->value.integer.value[i];
Markus Grabner705ecec2009-02-27 19:43:04 -0800238 changed = 1;
239 }
240
241 return changed;
242}
243
244/* control definition */
Markus Grabner1027f4762010-08-12 01:35:30 +0200245static struct snd_kcontrol_new line6_control_playback = {
Markus Grabner705ecec2009-02-27 19:43:04 -0800246 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
247 .name = "PCM Playback Volume",
248 .index = 0,
249 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
Markus Grabner1027f4762010-08-12 01:35:30 +0200250 .info = snd_line6_control_playback_info,
251 .get = snd_line6_control_playback_get,
252 .put = snd_line6_control_playback_put
Markus Grabner705ecec2009-02-27 19:43:04 -0800253};
254
255/*
256 Cleanup the PCM device.
257*/
258static void line6_cleanup_pcm(struct snd_pcm *pcm)
259{
260 int i;
261 struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
262
Markus Grabner1027f4762010-08-12 01:35:30 +0200263#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
264 device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
265 device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
266#endif
267
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800268 for (i = LINE6_ISO_BUFFERS; i--;) {
269 if (line6pcm->urb_audio_out[i]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800270 usb_kill_urb(line6pcm->urb_audio_out[i]);
271 usb_free_urb(line6pcm->urb_audio_out[i]);
272 }
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800273 if (line6pcm->urb_audio_in[i]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800274 usb_kill_urb(line6pcm->urb_audio_in[i]);
275 usb_free_urb(line6pcm->urb_audio_in[i]);
276 }
277 }
278}
279
280/* create a PCM device */
281static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
282{
283 struct snd_pcm *pcm;
284 int err;
285
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800286 err = snd_pcm_new(line6pcm->line6->card,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200287 (char *)line6pcm->line6->properties->name,
288 0, 1, 1, &pcm);
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800289 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800290 return err;
291
292 pcm->private_data = line6pcm;
293 pcm->private_free = line6_cleanup_pcm;
294 line6pcm->pcm = pcm;
295 strcpy(pcm->name, line6pcm->line6->properties->name);
296
297 /* set operators */
Shawn Bohrerafb90912009-11-15 22:17:57 -0600298 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
299 &snd_line6_playback_ops);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200300 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
Markus Grabner705ecec2009-02-27 19:43:04 -0800301
302 /* pre-allocation of buffers */
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800303 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200304 snd_dma_continuous_data
305 (GFP_KERNEL), 64 * 1024,
306 128 * 1024);
Markus Grabner705ecec2009-02-27 19:43:04 -0800307
308 return 0;
309}
310
311/* PCM device destructor */
312static int snd_line6_pcm_free(struct snd_device *device)
313{
314 return 0;
315}
316
317/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200318 Stop substream if still running.
319*/
320static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
321{
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700322 if (substream->runtime && snd_pcm_running(substream))
Markus Grabner1027f4762010-08-12 01:35:30 +0200323 snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
Markus Grabner1027f4762010-08-12 01:35:30 +0200324}
325
326/*
327 Stop PCM stream.
328*/
329void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
330{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200331 pcm_disconnect_substream(get_substream
332 (line6pcm, SNDRV_PCM_STREAM_CAPTURE));
333 pcm_disconnect_substream(get_substream
334 (line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
Markus Grabner1027f4762010-08-12 01:35:30 +0200335 line6_unlink_wait_clear_audio_out_urbs(line6pcm);
336 line6_unlink_wait_clear_audio_in_urbs(line6pcm);
337}
338
339/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800340 Create and register the PCM device and mixer entries.
341 Create URBs for playback and capture.
342*/
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800343int line6_init_pcm(struct usb_line6 *line6,
344 struct line6_pcm_properties *properties)
Markus Grabner705ecec2009-02-27 19:43:04 -0800345{
346 static struct snd_device_ops pcm_ops = {
347 .dev_free = snd_line6_pcm_free,
348 };
349
350 int err;
351 int ep_read = 0, ep_write = 0;
352 struct snd_line6_pcm *line6pcm;
353
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800354 if (!(line6->properties->capabilities & LINE6_BIT_PCM))
Markus Grabnere1a164d2010-08-23 01:08:25 +0200355 return 0; /* skip PCM initialization and report success */
Markus Grabner705ecec2009-02-27 19:43:04 -0800356
357 /* initialize PCM subsystem based on product id: */
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800358 switch (line6->product) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800359 case LINE6_DEVID_BASSPODXT:
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800360 case LINE6_DEVID_BASSPODXTLIVE:
361 case LINE6_DEVID_BASSPODXTPRO:
362 case LINE6_DEVID_PODXT:
363 case LINE6_DEVID_PODXTLIVE:
364 case LINE6_DEVID_PODXTPRO:
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000365 case LINE6_DEVID_PODHD300:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200366 ep_read = 0x82;
Markus Grabner705ecec2009-02-27 19:43:04 -0800367 ep_write = 0x01;
368 break;
369
Markus Grabner4c6fb5f2011-12-05 23:51:53 +0100370 case LINE6_DEVID_PODHD500:
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800371 case LINE6_DEVID_PODX3:
372 case LINE6_DEVID_PODX3LIVE:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200373 ep_read = 0x86;
Markus Grabner705ecec2009-02-27 19:43:04 -0800374 ep_write = 0x02;
375 break;
376
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800377 case LINE6_DEVID_POCKETPOD:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200378 ep_read = 0x82;
Markus Grabner705ecec2009-02-27 19:43:04 -0800379 ep_write = 0x02;
380 break;
381
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800382 case LINE6_DEVID_GUITARPORT:
Markus Grabner1027f4762010-08-12 01:35:30 +0200383 case LINE6_DEVID_PODSTUDIO_GX:
384 case LINE6_DEVID_PODSTUDIO_UX1:
385 case LINE6_DEVID_PODSTUDIO_UX2:
Markus Grabner705ecec2009-02-27 19:43:04 -0800386 case LINE6_DEVID_TONEPORT_GX:
Markus Grabner1027f4762010-08-12 01:35:30 +0200387 case LINE6_DEVID_TONEPORT_UX1:
388 case LINE6_DEVID_TONEPORT_UX2:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200389 ep_read = 0x82;
Markus Grabner705ecec2009-02-27 19:43:04 -0800390 ep_write = 0x01;
391 break;
392
Markus Grabner1027f4762010-08-12 01:35:30 +0200393 /* this is for interface_number == 1:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200394 case LINE6_DEVID_TONEPORT_UX2:
395 case LINE6_DEVID_PODSTUDIO_UX2:
396 ep_read = 0x87;
397 ep_write = 0x00;
398 break;
399 */
Markus Grabner705ecec2009-02-27 19:43:04 -0800400
401 default:
402 MISSING_CASE;
403 }
404
405 line6pcm = kzalloc(sizeof(struct snd_line6_pcm), GFP_KERNEL);
406
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800407 if (line6pcm == NULL)
Markus Grabner705ecec2009-02-27 19:43:04 -0800408 return -ENOMEM;
409
Markus Grabner1027f4762010-08-12 01:35:30 +0200410 line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
411 line6pcm->volume_monitor = 255;
Markus Grabner705ecec2009-02-27 19:43:04 -0800412 line6pcm->line6 = line6;
413 line6pcm->ep_audio_read = ep_read;
414 line6pcm->ep_audio_write = ep_write;
Stefan Hajnoczi3b08db32011-11-23 08:20:44 +0000415
416 /* Read and write buffers are sized identically, so choose minimum */
417 line6pcm->max_packet_size = min(
418 usb_maxpacket(line6->usbdev,
419 usb_rcvisocpipe(line6->usbdev, ep_read), 0),
420 usb_maxpacket(line6->usbdev,
421 usb_sndisocpipe(line6->usbdev, ep_write), 1));
422
Markus Grabner705ecec2009-02-27 19:43:04 -0800423 line6pcm->properties = properties;
424 line6->line6pcm = line6pcm;
425
426 /* PCM device: */
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800427 err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
428 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800429 return err;
430
431 snd_card_set_dev(line6->card, line6->ifcdev);
432
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800433 err = snd_line6_new_pcm(line6pcm);
434 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800435 return err;
436
437 spin_lock_init(&line6pcm->lock_audio_out);
438 spin_lock_init(&line6pcm->lock_audio_in);
439 spin_lock_init(&line6pcm->lock_trigger);
440
Markus Grabner1027f4762010-08-12 01:35:30 +0200441 err = line6_create_audio_out_urbs(line6pcm);
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800442 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800443 return err;
444
Markus Grabner1027f4762010-08-12 01:35:30 +0200445 err = line6_create_audio_in_urbs(line6pcm);
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800446 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800447 return err;
448
449 /* mixer: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200450 err =
451 snd_ctl_add(line6->card,
452 snd_ctl_new1(&line6_control_playback, line6pcm));
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800453 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800454 return err;
455
Markus Grabner1027f4762010-08-12 01:35:30 +0200456#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
457 /* impulse response test: */
458 err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
459 if (err < 0)
460 return err;
461
462 err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
463 if (err < 0)
464 return err;
465
466 line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
467#endif
468
Markus Grabner705ecec2009-02-27 19:43:04 -0800469 return 0;
470}
471
472/* prepare pcm callback */
473int snd_line6_prepare(struct snd_pcm_substream *substream)
474{
475 struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
476
Stefan Hajnoczi665f3f52011-12-10 02:12:31 +0100477 switch (substream->stream) {
478 case SNDRV_PCM_STREAM_PLAYBACK:
479 line6_unlink_wait_clear_audio_out_urbs(line6pcm);
480 break;
481
482 case SNDRV_PCM_STREAM_CAPTURE:
483 line6_unlink_wait_clear_audio_in_urbs(line6pcm);
484 break;
485
486 default:
487 MISSING_CASE;
488 }
489
490
Greg Kroah-Hartman68dc3dd2009-02-27 22:43:30 -0800491 if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
Markus Grabner1027f4762010-08-12 01:35:30 +0200492 line6pcm->count_out = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800493 line6pcm->pos_out = 0;
494 line6pcm->pos_out_done = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800495 line6pcm->bytes_out = 0;
Markus Grabner1027f4762010-08-12 01:35:30 +0200496 line6pcm->count_in = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800497 line6pcm->pos_in_done = 0;
498 line6pcm->bytes_in = 0;
499 }
500
501 return 0;
502}