diff options
author | Takashi Iwai <tiwai@suse.de> | 2015-01-12 16:29:57 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2015-01-12 16:29:57 -0500 |
commit | 61864d844c296933d40c02683252bbea5193b101 (patch) | |
tree | af106a2061e9b33dfbffdf761406cf5ff890ba2d /sound/usb | |
parent | d29b854fe9036a505af373ac485b2110ebae6ccd (diff) |
ALSA: move line6 usb driver into sound/usb
Promote line6 driver from staging to sound/usb/line6 directory, and
maintain through sound subsystem tree.
This commit just moves the code and adapts Makefile / Kconfig.
The further renames and misc cleanups will follow.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/usb')
28 files changed, 5779 insertions, 0 deletions
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index d393153c474f..a452ad7cec40 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -160,5 +160,7 @@ config SND_BCD2000 | |||
160 | To compile this driver as a module, choose M here: the module | 160 | To compile this driver as a module, choose M here: the module |
161 | will be called snd-bcd2000. | 161 | will be called snd-bcd2000. |
162 | 162 | ||
163 | source "sound/usb/line6/Kconfig" | ||
164 | |||
163 | endif # SND_USB | 165 | endif # SND_USB |
164 | 166 | ||
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index bcee4060fd18..54045b745d11 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
@@ -25,3 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o | |||
25 | obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o | 25 | obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o |
26 | 26 | ||
27 | obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ | 27 | obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ |
28 | obj-$(CONFIG_LINE6_USB) += line6/ | ||
diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig new file mode 100644 index 000000000000..4f1219b4c692 --- /dev/null +++ b/sound/usb/line6/Kconfig | |||
@@ -0,0 +1,38 @@ | |||
1 | menuconfig LINE6_USB | ||
2 | tristate "Line6 USB support" | ||
3 | depends on USB && SND | ||
4 | select SND_RAWMIDI | ||
5 | select SND_PCM | ||
6 | help | ||
7 | This is a driver for the guitar amp, cab, and effects modeller | ||
8 | PODxt Pro by Line6 (and similar devices), supporting the | ||
9 | following features: | ||
10 | * Reading/writing individual parameters | ||
11 | * Reading/writing complete channel, effects setup, and amp | ||
12 | setup data | ||
13 | * Channel switching | ||
14 | * Virtual MIDI interface | ||
15 | * Tuner access | ||
16 | * Playback/capture/mixer device for any ALSA-compatible PCM | ||
17 | audio application | ||
18 | * Signal routing (record clean/processed guitar signal, | ||
19 | re-amping) | ||
20 | |||
21 | Preliminary support for the Variax Workbench and TonePort | ||
22 | devices is included. | ||
23 | |||
24 | if LINE6_USB | ||
25 | |||
26 | config LINE6_USB_IMPULSE_RESPONSE | ||
27 | bool "measure impulse response" | ||
28 | default n | ||
29 | help | ||
30 | Say Y here to add code to measure the impulse response of a Line6 | ||
31 | device. This is more accurate than user-space methods since it | ||
32 | bypasses any PCM data buffering (e.g., by ALSA or jack). This is | ||
33 | useful for assessing the performance of new devices, but is not | ||
34 | required for normal operation. | ||
35 | |||
36 | If unsure, say N. | ||
37 | |||
38 | endif # LINE6_USB | ||
diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile new file mode 100644 index 000000000000..ae5c374b0f87 --- /dev/null +++ b/sound/usb/line6/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | obj-$(CONFIG_LINE6_USB) += line6usb.o | ||
2 | |||
3 | line6usb-y := \ | ||
4 | audio.o \ | ||
5 | capture.o \ | ||
6 | driver.o \ | ||
7 | midi.o \ | ||
8 | midibuf.o \ | ||
9 | pcm.o \ | ||
10 | playback.o \ | ||
11 | pod.o \ | ||
12 | toneport.o \ | ||
13 | variax.o \ | ||
14 | podhd.o | ||
diff --git a/sound/usb/line6/audio.c b/sound/usb/line6/audio.c new file mode 100644 index 000000000000..171d80c1b020 --- /dev/null +++ b/sound/usb/line6/audio.c | |||
@@ -0,0 +1,71 @@ | |||
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 <sound/core.h> | ||
13 | #include <sound/initval.h> | ||
14 | #include <linux/export.h> | ||
15 | |||
16 | #include "driver.h" | ||
17 | #include "audio.h" | ||
18 | |||
19 | /* | ||
20 | Initialize the Line6 USB audio system. | ||
21 | */ | ||
22 | int line6_init_audio(struct usb_line6 *line6) | ||
23 | { | ||
24 | struct snd_card *card; | ||
25 | int err; | ||
26 | |||
27 | err = snd_card_new(line6->ifcdev, | ||
28 | SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, | ||
29 | THIS_MODULE, 0, &card); | ||
30 | if (err < 0) | ||
31 | return err; | ||
32 | |||
33 | line6->card = card; | ||
34 | |||
35 | strcpy(card->id, line6->properties->id); | ||
36 | strcpy(card->driver, DRIVER_NAME); | ||
37 | strcpy(card->shortname, line6->properties->name); | ||
38 | /* longname is 80 chars - see asound.h */ | ||
39 | sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name, | ||
40 | dev_name(line6->ifcdev)); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | Register the Line6 USB audio system. | ||
46 | */ | ||
47 | int line6_register_audio(struct usb_line6 *line6) | ||
48 | { | ||
49 | int err; | ||
50 | |||
51 | err = snd_card_register(line6->card); | ||
52 | if (err < 0) | ||
53 | return err; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | Cleanup the Line6 USB audio system. | ||
60 | */ | ||
61 | void line6_cleanup_audio(struct usb_line6 *line6) | ||
62 | { | ||
63 | struct snd_card *card = line6->card; | ||
64 | |||
65 | if (card == NULL) | ||
66 | return; | ||
67 | |||
68 | snd_card_disconnect(card); | ||
69 | snd_card_free(card); | ||
70 | line6->card = NULL; | ||
71 | } | ||
diff --git a/sound/usb/line6/audio.h b/sound/usb/line6/audio.h new file mode 100644 index 000000000000..5f8a09a0fa95 --- /dev/null +++ b/sound/usb/line6/audio.h | |||
@@ -0,0 +1,21 @@ | |||
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 | #ifndef AUDIO_H | ||
13 | #define AUDIO_H | ||
14 | |||
15 | #include "driver.h" | ||
16 | |||
17 | extern void line6_cleanup_audio(struct usb_line6 *); | ||
18 | extern int line6_init_audio(struct usb_line6 *); | ||
19 | extern int line6_register_audio(struct usb_line6 *); | ||
20 | |||
21 | #endif | ||
diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c new file mode 100644 index 000000000000..f24c7c5e0a3e --- /dev/null +++ b/sound/usb/line6/capture.c | |||
@@ -0,0 +1,433 @@ | |||
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 <sound/core.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include <sound/pcm_params.h> | ||
16 | |||
17 | #include "audio.h" | ||
18 | #include "capture.h" | ||
19 | #include "driver.h" | ||
20 | #include "pcm.h" | ||
21 | #include "pod.h" | ||
22 | |||
23 | /* | ||
24 | Find a free URB and submit it. | ||
25 | */ | ||
26 | static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) | ||
27 | { | ||
28 | int index; | ||
29 | unsigned long flags; | ||
30 | int i, urb_size; | ||
31 | int ret; | ||
32 | struct urb *urb_in; | ||
33 | |||
34 | spin_lock_irqsave(&line6pcm->lock_audio_in, flags); | ||
35 | index = | ||
36 | find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); | ||
37 | |||
38 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { | ||
39 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); | ||
40 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); | ||
41 | return -EINVAL; | ||
42 | } | ||
43 | |||
44 | urb_in = line6pcm->urb_audio_in[index]; | ||
45 | urb_size = 0; | ||
46 | |||
47 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | ||
48 | struct usb_iso_packet_descriptor *fin = | ||
49 | &urb_in->iso_frame_desc[i]; | ||
50 | fin->offset = urb_size; | ||
51 | fin->length = line6pcm->max_packet_size; | ||
52 | urb_size += line6pcm->max_packet_size; | ||
53 | } | ||
54 | |||
55 | urb_in->transfer_buffer = | ||
56 | line6pcm->buffer_in + | ||
57 | index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; | ||
58 | urb_in->transfer_buffer_length = urb_size; | ||
59 | urb_in->context = line6pcm; | ||
60 | |||
61 | ret = usb_submit_urb(urb_in, GFP_ATOMIC); | ||
62 | |||
63 | if (ret == 0) | ||
64 | set_bit(index, &line6pcm->active_urb_in); | ||
65 | else | ||
66 | dev_err(line6pcm->line6->ifcdev, | ||
67 | "URB in #%d submission failed (%d)\n", index, ret); | ||
68 | |||
69 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | /* | ||
74 | Submit all currently available capture URBs. | ||
75 | */ | ||
76 | int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) | ||
77 | { | ||
78 | int ret, i; | ||
79 | |||
80 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
81 | ret = submit_audio_in_urb(line6pcm); | ||
82 | if (ret < 0) | ||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | Unlink all currently active capture URBs. | ||
91 | */ | ||
92 | void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) | ||
93 | { | ||
94 | unsigned int i; | ||
95 | |||
96 | for (i = LINE6_ISO_BUFFERS; i--;) { | ||
97 | if (test_bit(i, &line6pcm->active_urb_in)) { | ||
98 | if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { | ||
99 | struct urb *u = line6pcm->urb_audio_in[i]; | ||
100 | |||
101 | usb_unlink_urb(u); | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /* | ||
108 | Wait until unlinking of all currently active capture URBs has been | ||
109 | finished. | ||
110 | */ | ||
111 | void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) | ||
112 | { | ||
113 | int timeout = HZ; | ||
114 | unsigned int i; | ||
115 | int alive; | ||
116 | |||
117 | do { | ||
118 | alive = 0; | ||
119 | for (i = LINE6_ISO_BUFFERS; i--;) { | ||
120 | if (test_bit(i, &line6pcm->active_urb_in)) | ||
121 | alive++; | ||
122 | } | ||
123 | if (!alive) | ||
124 | break; | ||
125 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
126 | schedule_timeout(1); | ||
127 | } while (--timeout > 0); | ||
128 | if (alive) | ||
129 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | Unlink all currently active capture URBs, and wait for finishing. | ||
134 | */ | ||
135 | void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) | ||
136 | { | ||
137 | line6_unlink_audio_in_urbs(line6pcm); | ||
138 | line6_wait_clear_audio_in_urbs(line6pcm); | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | Copy data into ALSA capture buffer. | ||
143 | */ | ||
144 | void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) | ||
145 | { | ||
146 | struct snd_pcm_substream *substream = | ||
147 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
148 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
149 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; | ||
150 | int frames = fsize / bytes_per_frame; | ||
151 | |||
152 | if (runtime == NULL) | ||
153 | return; | ||
154 | |||
155 | if (line6pcm->pos_in_done + frames > runtime->buffer_size) { | ||
156 | /* | ||
157 | The transferred area goes over buffer boundary, | ||
158 | copy two separate chunks. | ||
159 | */ | ||
160 | int len; | ||
161 | |||
162 | len = runtime->buffer_size - line6pcm->pos_in_done; | ||
163 | |||
164 | if (len > 0) { | ||
165 | memcpy(runtime->dma_area + | ||
166 | line6pcm->pos_in_done * bytes_per_frame, fbuf, | ||
167 | len * bytes_per_frame); | ||
168 | memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, | ||
169 | (frames - len) * bytes_per_frame); | ||
170 | } else { | ||
171 | /* this is somewhat paranoid */ | ||
172 | dev_err(line6pcm->line6->ifcdev, | ||
173 | "driver bug: len = %d\n", len); | ||
174 | } | ||
175 | } else { | ||
176 | /* copy single chunk */ | ||
177 | memcpy(runtime->dma_area + | ||
178 | line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); | ||
179 | } | ||
180 | |||
181 | line6pcm->pos_in_done += frames; | ||
182 | if (line6pcm->pos_in_done >= runtime->buffer_size) | ||
183 | line6pcm->pos_in_done -= runtime->buffer_size; | ||
184 | } | ||
185 | |||
186 | void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) | ||
187 | { | ||
188 | struct snd_pcm_substream *substream = | ||
189 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
190 | |||
191 | line6pcm->bytes_in += length; | ||
192 | if (line6pcm->bytes_in >= line6pcm->period_in) { | ||
193 | line6pcm->bytes_in %= line6pcm->period_in; | ||
194 | snd_pcm_period_elapsed(substream); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm) | ||
199 | { | ||
200 | kfree(line6pcm->buffer_in); | ||
201 | line6pcm->buffer_in = NULL; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * Callback for completed capture URB. | ||
206 | */ | ||
207 | static void audio_in_callback(struct urb *urb) | ||
208 | { | ||
209 | int i, index, length = 0, shutdown = 0; | ||
210 | unsigned long flags; | ||
211 | |||
212 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; | ||
213 | |||
214 | line6pcm->last_frame_in = urb->start_frame; | ||
215 | |||
216 | /* find index of URB */ | ||
217 | for (index = 0; index < LINE6_ISO_BUFFERS; ++index) | ||
218 | if (urb == line6pcm->urb_audio_in[index]) | ||
219 | break; | ||
220 | |||
221 | spin_lock_irqsave(&line6pcm->lock_audio_in, flags); | ||
222 | |||
223 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | ||
224 | char *fbuf; | ||
225 | int fsize; | ||
226 | struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; | ||
227 | |||
228 | if (fin->status == -EXDEV) { | ||
229 | shutdown = 1; | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | fbuf = urb->transfer_buffer + fin->offset; | ||
234 | fsize = fin->actual_length; | ||
235 | |||
236 | if (fsize > line6pcm->max_packet_size) { | ||
237 | dev_err(line6pcm->line6->ifcdev, | ||
238 | "driver and/or device bug: packet too large (%d > %d)\n", | ||
239 | fsize, line6pcm->max_packet_size); | ||
240 | } | ||
241 | |||
242 | length += fsize; | ||
243 | |||
244 | /* the following assumes LINE6_ISO_PACKETS == 1: */ | ||
245 | line6pcm->prev_fbuf = fbuf; | ||
246 | line6pcm->prev_fsize = fsize; | ||
247 | |||
248 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
249 | if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) | ||
250 | #endif | ||
251 | if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, | ||
252 | &line6pcm->flags) && (fsize > 0)) | ||
253 | line6_capture_copy(line6pcm, fbuf, fsize); | ||
254 | } | ||
255 | |||
256 | clear_bit(index, &line6pcm->active_urb_in); | ||
257 | |||
258 | if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) | ||
259 | shutdown = 1; | ||
260 | |||
261 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); | ||
262 | |||
263 | if (!shutdown) { | ||
264 | submit_audio_in_urb(line6pcm); | ||
265 | |||
266 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
267 | if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) | ||
268 | #endif | ||
269 | if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, | ||
270 | &line6pcm->flags)) | ||
271 | line6_capture_check_period(line6pcm, length); | ||
272 | } | ||
273 | } | ||
274 | |||
275 | /* open capture callback */ | ||
276 | static int snd_line6_capture_open(struct snd_pcm_substream *substream) | ||
277 | { | ||
278 | int err; | ||
279 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
280 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
281 | |||
282 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, | ||
283 | SNDRV_PCM_HW_PARAM_RATE, | ||
284 | (&line6pcm-> | ||
285 | properties->snd_line6_rates)); | ||
286 | if (err < 0) | ||
287 | return err; | ||
288 | |||
289 | runtime->hw = line6pcm->properties->snd_line6_capture_hw; | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | /* close capture callback */ | ||
294 | static int snd_line6_capture_close(struct snd_pcm_substream *substream) | ||
295 | { | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* hw_params capture callback */ | ||
300 | static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, | ||
301 | struct snd_pcm_hw_params *hw_params) | ||
302 | { | ||
303 | int ret; | ||
304 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
305 | |||
306 | /* -- Florian Demski [FD] */ | ||
307 | /* don't ask me why, but this fixes the bug on my machine */ | ||
308 | if (line6pcm == NULL) { | ||
309 | if (substream->pcm == NULL) | ||
310 | return -ENOMEM; | ||
311 | if (substream->pcm->private_data == NULL) | ||
312 | return -ENOMEM; | ||
313 | substream->private_data = substream->pcm->private_data; | ||
314 | line6pcm = snd_pcm_substream_chip(substream); | ||
315 | } | ||
316 | /* -- [FD] end */ | ||
317 | |||
318 | ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); | ||
319 | |||
320 | if (ret < 0) | ||
321 | return ret; | ||
322 | |||
323 | ret = snd_pcm_lib_malloc_pages(substream, | ||
324 | params_buffer_bytes(hw_params)); | ||
325 | if (ret < 0) { | ||
326 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | line6pcm->period_in = params_period_bytes(hw_params); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | /* hw_free capture callback */ | ||
335 | static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) | ||
336 | { | ||
337 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
338 | |||
339 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER); | ||
340 | return snd_pcm_lib_free_pages(substream); | ||
341 | } | ||
342 | |||
343 | /* trigger callback */ | ||
344 | int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) | ||
345 | { | ||
346 | int err; | ||
347 | |||
348 | switch (cmd) { | ||
349 | case SNDRV_PCM_TRIGGER_START: | ||
350 | #ifdef CONFIG_PM | ||
351 | case SNDRV_PCM_TRIGGER_RESUME: | ||
352 | #endif | ||
353 | err = line6_pcm_acquire(line6pcm, | ||
354 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); | ||
355 | |||
356 | if (err < 0) | ||
357 | return err; | ||
358 | |||
359 | break; | ||
360 | |||
361 | case SNDRV_PCM_TRIGGER_STOP: | ||
362 | #ifdef CONFIG_PM | ||
363 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
364 | #endif | ||
365 | err = line6_pcm_release(line6pcm, | ||
366 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); | ||
367 | |||
368 | if (err < 0) | ||
369 | return err; | ||
370 | |||
371 | break; | ||
372 | |||
373 | default: | ||
374 | return -EINVAL; | ||
375 | } | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /* capture pointer callback */ | ||
381 | static snd_pcm_uframes_t | ||
382 | snd_line6_capture_pointer(struct snd_pcm_substream *substream) | ||
383 | { | ||
384 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
385 | |||
386 | return line6pcm->pos_in_done; | ||
387 | } | ||
388 | |||
389 | /* capture operators */ | ||
390 | struct snd_pcm_ops snd_line6_capture_ops = { | ||
391 | .open = snd_line6_capture_open, | ||
392 | .close = snd_line6_capture_close, | ||
393 | .ioctl = snd_pcm_lib_ioctl, | ||
394 | .hw_params = snd_line6_capture_hw_params, | ||
395 | .hw_free = snd_line6_capture_hw_free, | ||
396 | .prepare = snd_line6_prepare, | ||
397 | .trigger = snd_line6_trigger, | ||
398 | .pointer = snd_line6_capture_pointer, | ||
399 | }; | ||
400 | |||
401 | int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) | ||
402 | { | ||
403 | struct usb_line6 *line6 = line6pcm->line6; | ||
404 | int i; | ||
405 | |||
406 | /* create audio URBs and fill in constant values: */ | ||
407 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
408 | struct urb *urb; | ||
409 | |||
410 | /* URB for audio in: */ | ||
411 | urb = line6pcm->urb_audio_in[i] = | ||
412 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); | ||
413 | |||
414 | if (urb == NULL) { | ||
415 | dev_err(line6->ifcdev, "Out of memory\n"); | ||
416 | return -ENOMEM; | ||
417 | } | ||
418 | |||
419 | urb->dev = line6->usbdev; | ||
420 | urb->pipe = | ||
421 | usb_rcvisocpipe(line6->usbdev, | ||
422 | line6->properties->ep_audio_r & | ||
423 | USB_ENDPOINT_NUMBER_MASK); | ||
424 | urb->transfer_flags = URB_ISO_ASAP; | ||
425 | urb->start_frame = -1; | ||
426 | urb->number_of_packets = LINE6_ISO_PACKETS; | ||
427 | urb->interval = LINE6_ISO_INTERVAL; | ||
428 | urb->error_count = 0; | ||
429 | urb->complete = audio_in_callback; | ||
430 | } | ||
431 | |||
432 | return 0; | ||
433 | } | ||
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h new file mode 100644 index 000000000000..4157bcb598a9 --- /dev/null +++ b/sound/usb/line6/capture.h | |||
@@ -0,0 +1,35 @@ | |||
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 | #ifndef CAPTURE_H | ||
13 | #define CAPTURE_H | ||
14 | |||
15 | #include <sound/pcm.h> | ||
16 | |||
17 | #include "driver.h" | ||
18 | #include "pcm.h" | ||
19 | |||
20 | extern struct snd_pcm_ops snd_line6_capture_ops; | ||
21 | |||
22 | extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, | ||
23 | int fsize); | ||
24 | extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, | ||
25 | int length); | ||
26 | extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm); | ||
27 | extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm); | ||
28 | extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); | ||
29 | extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm); | ||
30 | extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm | ||
31 | *line6pcm); | ||
32 | extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm); | ||
33 | extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd); | ||
34 | |||
35 | #endif | ||
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c new file mode 100644 index 000000000000..fc852f6ab8bc --- /dev/null +++ b/sound/usb/line6/driver.c | |||
@@ -0,0 +1,1114 @@ | |||
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/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/usb.h> | ||
16 | |||
17 | #include "audio.h" | ||
18 | #include "capture.h" | ||
19 | #include "driver.h" | ||
20 | #include "midi.h" | ||
21 | #include "playback.h" | ||
22 | #include "pod.h" | ||
23 | #include "podhd.h" | ||
24 | #include "revision.h" | ||
25 | #include "toneport.h" | ||
26 | #include "usbdefs.h" | ||
27 | #include "variax.h" | ||
28 | |||
29 | #define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>" | ||
30 | #define DRIVER_DESC "Line6 USB Driver" | ||
31 | #define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION | ||
32 | |||
33 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) | ||
34 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) | ||
35 | |||
36 | /* table of devices that work with this driver */ | ||
37 | static const struct usb_device_id line6_id_table[] = { | ||
38 | { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, | ||
39 | { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, | ||
40 | { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, | ||
41 | { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, | ||
42 | { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, | ||
43 | { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, | ||
44 | { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, | ||
45 | { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, | ||
46 | { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, | ||
47 | { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, | ||
48 | { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, | ||
49 | { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, | ||
50 | { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, | ||
51 | { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, | ||
52 | { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, | ||
53 | { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, | ||
54 | { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, | ||
55 | { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, | ||
56 | { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, | ||
57 | { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, | ||
58 | {} | ||
59 | }; | ||
60 | |||
61 | MODULE_DEVICE_TABLE(usb, line6_id_table); | ||
62 | |||
63 | static const struct line6_properties line6_properties_table[] = { | ||
64 | [LINE6_BASSPODXT] = { | ||
65 | .id = "BassPODxt", | ||
66 | .name = "BassPODxt", | ||
67 | .capabilities = LINE6_CAP_CONTROL | ||
68 | | LINE6_CAP_PCM | ||
69 | | LINE6_CAP_HWMON, | ||
70 | .altsetting = 5, | ||
71 | .ep_ctrl_r = 0x84, | ||
72 | .ep_ctrl_w = 0x03, | ||
73 | .ep_audio_r = 0x82, | ||
74 | .ep_audio_w = 0x01, | ||
75 | }, | ||
76 | [LINE6_BASSPODXTLIVE] = { | ||
77 | .id = "BassPODxtLive", | ||
78 | .name = "BassPODxt Live", | ||
79 | .capabilities = LINE6_CAP_CONTROL | ||
80 | | LINE6_CAP_PCM | ||
81 | | LINE6_CAP_HWMON, | ||
82 | .altsetting = 1, | ||
83 | .ep_ctrl_r = 0x84, | ||
84 | .ep_ctrl_w = 0x03, | ||
85 | .ep_audio_r = 0x82, | ||
86 | .ep_audio_w = 0x01, | ||
87 | }, | ||
88 | [LINE6_BASSPODXTPRO] = { | ||
89 | .id = "BassPODxtPro", | ||
90 | .name = "BassPODxt Pro", | ||
91 | .capabilities = LINE6_CAP_CONTROL | ||
92 | | LINE6_CAP_PCM | ||
93 | | LINE6_CAP_HWMON, | ||
94 | .altsetting = 5, | ||
95 | .ep_ctrl_r = 0x84, | ||
96 | .ep_ctrl_w = 0x03, | ||
97 | .ep_audio_r = 0x82, | ||
98 | .ep_audio_w = 0x01, | ||
99 | }, | ||
100 | [LINE6_GUITARPORT] = { | ||
101 | .id = "GuitarPort", | ||
102 | .name = "GuitarPort", | ||
103 | .capabilities = LINE6_CAP_PCM, | ||
104 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
105 | /* no control channel */ | ||
106 | .ep_audio_r = 0x82, | ||
107 | .ep_audio_w = 0x01, | ||
108 | }, | ||
109 | [LINE6_POCKETPOD] = { | ||
110 | .id = "PocketPOD", | ||
111 | .name = "Pocket POD", | ||
112 | .capabilities = LINE6_CAP_CONTROL, | ||
113 | .altsetting = 0, | ||
114 | .ep_ctrl_r = 0x82, | ||
115 | .ep_ctrl_w = 0x02, | ||
116 | /* no audio channel */ | ||
117 | }, | ||
118 | [LINE6_PODHD300] = { | ||
119 | .id = "PODHD300", | ||
120 | .name = "POD HD300", | ||
121 | .capabilities = LINE6_CAP_CONTROL | ||
122 | | LINE6_CAP_PCM | ||
123 | | LINE6_CAP_HWMON, | ||
124 | .altsetting = 5, | ||
125 | .ep_ctrl_r = 0x84, | ||
126 | .ep_ctrl_w = 0x03, | ||
127 | .ep_audio_r = 0x82, | ||
128 | .ep_audio_w = 0x01, | ||
129 | }, | ||
130 | [LINE6_PODHD400] = { | ||
131 | .id = "PODHD400", | ||
132 | .name = "POD HD400", | ||
133 | .capabilities = LINE6_CAP_CONTROL | ||
134 | | LINE6_CAP_PCM | ||
135 | | LINE6_CAP_HWMON, | ||
136 | .altsetting = 5, | ||
137 | .ep_ctrl_r = 0x84, | ||
138 | .ep_ctrl_w = 0x03, | ||
139 | .ep_audio_r = 0x82, | ||
140 | .ep_audio_w = 0x01, | ||
141 | }, | ||
142 | [LINE6_PODHD500_0] = { | ||
143 | .id = "PODHD500", | ||
144 | .name = "POD HD500", | ||
145 | .capabilities = LINE6_CAP_CONTROL | ||
146 | | LINE6_CAP_PCM | ||
147 | | LINE6_CAP_HWMON, | ||
148 | .altsetting = 1, | ||
149 | .ep_ctrl_r = 0x81, | ||
150 | .ep_ctrl_w = 0x01, | ||
151 | .ep_audio_r = 0x86, | ||
152 | .ep_audio_w = 0x02, | ||
153 | }, | ||
154 | [LINE6_PODHD500_1] = { | ||
155 | .id = "PODHD500", | ||
156 | .name = "POD HD500", | ||
157 | .capabilities = LINE6_CAP_CONTROL | ||
158 | | LINE6_CAP_PCM | ||
159 | | LINE6_CAP_HWMON, | ||
160 | .altsetting = 1, | ||
161 | .ep_ctrl_r = 0x81, | ||
162 | .ep_ctrl_w = 0x01, | ||
163 | .ep_audio_r = 0x86, | ||
164 | .ep_audio_w = 0x02, | ||
165 | }, | ||
166 | [LINE6_PODSTUDIO_GX] = { | ||
167 | .id = "PODStudioGX", | ||
168 | .name = "POD Studio GX", | ||
169 | .capabilities = LINE6_CAP_PCM, | ||
170 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
171 | /* no control channel */ | ||
172 | .ep_audio_r = 0x82, | ||
173 | .ep_audio_w = 0x01, | ||
174 | }, | ||
175 | [LINE6_PODSTUDIO_UX1] = { | ||
176 | .id = "PODStudioUX1", | ||
177 | .name = "POD Studio UX1", | ||
178 | .capabilities = LINE6_CAP_PCM, | ||
179 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
180 | /* no control channel */ | ||
181 | .ep_audio_r = 0x82, | ||
182 | .ep_audio_w = 0x01, | ||
183 | }, | ||
184 | [LINE6_PODSTUDIO_UX2] = { | ||
185 | .id = "PODStudioUX2", | ||
186 | .name = "POD Studio UX2", | ||
187 | .capabilities = LINE6_CAP_PCM, | ||
188 | .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ | ||
189 | /* no control channel */ | ||
190 | .ep_audio_r = 0x82, | ||
191 | .ep_audio_w = 0x01, | ||
192 | }, | ||
193 | [LINE6_PODXT] = { | ||
194 | .id = "PODxt", | ||
195 | .name = "PODxt", | ||
196 | .capabilities = LINE6_CAP_CONTROL | ||
197 | | LINE6_CAP_PCM | ||
198 | | LINE6_CAP_HWMON, | ||
199 | .altsetting = 5, | ||
200 | .ep_ctrl_r = 0x84, | ||
201 | .ep_ctrl_w = 0x03, | ||
202 | .ep_audio_r = 0x82, | ||
203 | .ep_audio_w = 0x01, | ||
204 | }, | ||
205 | [LINE6_PODXTLIVE_POD] = { | ||
206 | .id = "PODxtLive", | ||
207 | .name = "PODxt Live", | ||
208 | .capabilities = LINE6_CAP_CONTROL | ||
209 | | LINE6_CAP_PCM | ||
210 | | LINE6_CAP_HWMON, | ||
211 | .altsetting = 1, | ||
212 | .ep_ctrl_r = 0x84, | ||
213 | .ep_ctrl_w = 0x03, | ||
214 | .ep_audio_r = 0x82, | ||
215 | .ep_audio_w = 0x01, | ||
216 | }, | ||
217 | [LINE6_PODXTLIVE_VARIAX] = { | ||
218 | .id = "PODxtLive", | ||
219 | .name = "PODxt Live", | ||
220 | .capabilities = LINE6_CAP_CONTROL | ||
221 | | LINE6_CAP_PCM | ||
222 | | LINE6_CAP_HWMON, | ||
223 | .altsetting = 1, | ||
224 | .ep_ctrl_r = 0x86, | ||
225 | .ep_ctrl_w = 0x05, | ||
226 | .ep_audio_r = 0x82, | ||
227 | .ep_audio_w = 0x01, | ||
228 | }, | ||
229 | [LINE6_PODXTPRO] = { | ||
230 | .id = "PODxtPro", | ||
231 | .name = "PODxt Pro", | ||
232 | .capabilities = LINE6_CAP_CONTROL | ||
233 | | LINE6_CAP_PCM | ||
234 | | LINE6_CAP_HWMON, | ||
235 | .altsetting = 5, | ||
236 | .ep_ctrl_r = 0x84, | ||
237 | .ep_ctrl_w = 0x03, | ||
238 | .ep_audio_r = 0x82, | ||
239 | .ep_audio_w = 0x01, | ||
240 | }, | ||
241 | [LINE6_TONEPORT_GX] = { | ||
242 | .id = "TonePortGX", | ||
243 | .name = "TonePort GX", | ||
244 | .capabilities = LINE6_CAP_PCM, | ||
245 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
246 | /* no control channel */ | ||
247 | .ep_audio_r = 0x82, | ||
248 | .ep_audio_w = 0x01, | ||
249 | }, | ||
250 | [LINE6_TONEPORT_UX1] = { | ||
251 | .id = "TonePortUX1", | ||
252 | .name = "TonePort UX1", | ||
253 | .capabilities = LINE6_CAP_PCM, | ||
254 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
255 | /* no control channel */ | ||
256 | .ep_audio_r = 0x82, | ||
257 | .ep_audio_w = 0x01, | ||
258 | }, | ||
259 | [LINE6_TONEPORT_UX2] = { | ||
260 | .id = "TonePortUX2", | ||
261 | .name = "TonePort UX2", | ||
262 | .capabilities = LINE6_CAP_PCM, | ||
263 | .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ | ||
264 | /* no control channel */ | ||
265 | .ep_audio_r = 0x82, | ||
266 | .ep_audio_w = 0x01, | ||
267 | }, | ||
268 | [LINE6_VARIAX] = { | ||
269 | .id = "Variax", | ||
270 | .name = "Variax Workbench", | ||
271 | .capabilities = LINE6_CAP_CONTROL, | ||
272 | .altsetting = 1, | ||
273 | .ep_ctrl_r = 0x82, | ||
274 | .ep_ctrl_w = 0x01, | ||
275 | /* no audio channel */ | ||
276 | } | ||
277 | }; | ||
278 | |||
279 | /* | ||
280 | This is Line6's MIDI manufacturer ID. | ||
281 | */ | ||
282 | const unsigned char line6_midi_id[] = { | ||
283 | 0x00, 0x01, 0x0c | ||
284 | }; | ||
285 | |||
286 | /* | ||
287 | Code to request version of POD, Variax interface | ||
288 | (and maybe other devices). | ||
289 | */ | ||
290 | static const char line6_request_version[] = { | ||
291 | 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 | ||
292 | }; | ||
293 | |||
294 | /** | ||
295 | Class for asynchronous messages. | ||
296 | */ | ||
297 | struct message { | ||
298 | struct usb_line6 *line6; | ||
299 | const char *buffer; | ||
300 | int size; | ||
301 | int done; | ||
302 | }; | ||
303 | |||
304 | /* | ||
305 | Forward declarations. | ||
306 | */ | ||
307 | static void line6_data_received(struct urb *urb); | ||
308 | static int line6_send_raw_message_async_part(struct message *msg, | ||
309 | struct urb *urb); | ||
310 | |||
311 | /* | ||
312 | Start to listen on endpoint. | ||
313 | */ | ||
314 | static int line6_start_listen(struct usb_line6 *line6) | ||
315 | { | ||
316 | int err; | ||
317 | |||
318 | usb_fill_int_urb(line6->urb_listen, line6->usbdev, | ||
319 | usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), | ||
320 | line6->buffer_listen, LINE6_BUFSIZE_LISTEN, | ||
321 | line6_data_received, line6, line6->interval); | ||
322 | line6->urb_listen->actual_length = 0; | ||
323 | err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); | ||
324 | return err; | ||
325 | } | ||
326 | |||
327 | /* | ||
328 | Stop listening on endpoint. | ||
329 | */ | ||
330 | static void line6_stop_listen(struct usb_line6 *line6) | ||
331 | { | ||
332 | usb_kill_urb(line6->urb_listen); | ||
333 | } | ||
334 | |||
335 | /* | ||
336 | Send raw message in pieces of wMaxPacketSize bytes. | ||
337 | */ | ||
338 | int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, | ||
339 | int size) | ||
340 | { | ||
341 | int i, done = 0; | ||
342 | |||
343 | for (i = 0; i < size; i += line6->max_packet_size) { | ||
344 | int partial; | ||
345 | const char *frag_buf = buffer + i; | ||
346 | int frag_size = min(line6->max_packet_size, size - i); | ||
347 | int retval; | ||
348 | |||
349 | retval = usb_interrupt_msg(line6->usbdev, | ||
350 | usb_sndintpipe(line6->usbdev, | ||
351 | line6->properties->ep_ctrl_w), | ||
352 | (char *)frag_buf, frag_size, | ||
353 | &partial, LINE6_TIMEOUT * HZ); | ||
354 | |||
355 | if (retval) { | ||
356 | dev_err(line6->ifcdev, | ||
357 | "usb_interrupt_msg failed (%d)\n", retval); | ||
358 | break; | ||
359 | } | ||
360 | |||
361 | done += frag_size; | ||
362 | } | ||
363 | |||
364 | return done; | ||
365 | } | ||
366 | |||
367 | /* | ||
368 | Notification of completion of asynchronous request transmission. | ||
369 | */ | ||
370 | static void line6_async_request_sent(struct urb *urb) | ||
371 | { | ||
372 | struct message *msg = (struct message *)urb->context; | ||
373 | |||
374 | if (msg->done >= msg->size) { | ||
375 | usb_free_urb(urb); | ||
376 | kfree(msg); | ||
377 | } else | ||
378 | line6_send_raw_message_async_part(msg, urb); | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | Asynchronously send part of a raw message. | ||
383 | */ | ||
384 | static int line6_send_raw_message_async_part(struct message *msg, | ||
385 | struct urb *urb) | ||
386 | { | ||
387 | int retval; | ||
388 | struct usb_line6 *line6 = msg->line6; | ||
389 | int done = msg->done; | ||
390 | int bytes = min(msg->size - done, line6->max_packet_size); | ||
391 | |||
392 | usb_fill_int_urb(urb, line6->usbdev, | ||
393 | usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), | ||
394 | (char *)msg->buffer + done, bytes, | ||
395 | line6_async_request_sent, msg, line6->interval); | ||
396 | |||
397 | msg->done += bytes; | ||
398 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
399 | |||
400 | if (retval < 0) { | ||
401 | dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", | ||
402 | __func__, retval); | ||
403 | usb_free_urb(urb); | ||
404 | kfree(msg); | ||
405 | return retval; | ||
406 | } | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | /* | ||
412 | Setup and start timer. | ||
413 | */ | ||
414 | void line6_start_timer(struct timer_list *timer, unsigned int msecs, | ||
415 | void (*function)(unsigned long), unsigned long data) | ||
416 | { | ||
417 | setup_timer(timer, function, data); | ||
418 | timer->expires = jiffies + msecs * HZ / 1000; | ||
419 | add_timer(timer); | ||
420 | } | ||
421 | |||
422 | /* | ||
423 | Asynchronously send raw message. | ||
424 | */ | ||
425 | int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, | ||
426 | int size) | ||
427 | { | ||
428 | struct message *msg; | ||
429 | struct urb *urb; | ||
430 | |||
431 | /* create message: */ | ||
432 | msg = kmalloc(sizeof(struct message), GFP_ATOMIC); | ||
433 | if (msg == NULL) | ||
434 | return -ENOMEM; | ||
435 | |||
436 | /* create URB: */ | ||
437 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
438 | |||
439 | if (urb == NULL) { | ||
440 | kfree(msg); | ||
441 | dev_err(line6->ifcdev, "Out of memory\n"); | ||
442 | return -ENOMEM; | ||
443 | } | ||
444 | |||
445 | /* set message data: */ | ||
446 | msg->line6 = line6; | ||
447 | msg->buffer = buffer; | ||
448 | msg->size = size; | ||
449 | msg->done = 0; | ||
450 | |||
451 | /* start sending: */ | ||
452 | return line6_send_raw_message_async_part(msg, urb); | ||
453 | } | ||
454 | |||
455 | /* | ||
456 | Send asynchronous device version request. | ||
457 | */ | ||
458 | int line6_version_request_async(struct usb_line6 *line6) | ||
459 | { | ||
460 | char *buffer; | ||
461 | int retval; | ||
462 | |||
463 | buffer = kmemdup(line6_request_version, | ||
464 | sizeof(line6_request_version), GFP_ATOMIC); | ||
465 | if (buffer == NULL) { | ||
466 | dev_err(line6->ifcdev, "Out of memory"); | ||
467 | return -ENOMEM; | ||
468 | } | ||
469 | |||
470 | retval = line6_send_raw_message_async(line6, buffer, | ||
471 | sizeof(line6_request_version)); | ||
472 | kfree(buffer); | ||
473 | return retval; | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | Send sysex message in pieces of wMaxPacketSize bytes. | ||
478 | */ | ||
479 | int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, | ||
480 | int size) | ||
481 | { | ||
482 | return line6_send_raw_message(line6, buffer, | ||
483 | size + SYSEX_EXTRA_SIZE) - | ||
484 | SYSEX_EXTRA_SIZE; | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | Allocate buffer for sysex message and prepare header. | ||
489 | @param code sysex message code | ||
490 | @param size number of bytes between code and sysex end | ||
491 | */ | ||
492 | char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, | ||
493 | int size) | ||
494 | { | ||
495 | char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); | ||
496 | |||
497 | if (!buffer) | ||
498 | return NULL; | ||
499 | |||
500 | buffer[0] = LINE6_SYSEX_BEGIN; | ||
501 | memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); | ||
502 | buffer[sizeof(line6_midi_id) + 1] = code1; | ||
503 | buffer[sizeof(line6_midi_id) + 2] = code2; | ||
504 | buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; | ||
505 | return buffer; | ||
506 | } | ||
507 | |||
508 | /* | ||
509 | Notification of data received from the Line6 device. | ||
510 | */ | ||
511 | static void line6_data_received(struct urb *urb) | ||
512 | { | ||
513 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; | ||
514 | struct midi_buffer *mb = &line6->line6midi->midibuf_in; | ||
515 | int done; | ||
516 | |||
517 | if (urb->status == -ESHUTDOWN) | ||
518 | return; | ||
519 | |||
520 | done = | ||
521 | line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); | ||
522 | |||
523 | if (done < urb->actual_length) { | ||
524 | line6_midibuf_ignore(mb, done); | ||
525 | dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", | ||
526 | done, urb->actual_length); | ||
527 | } | ||
528 | |||
529 | for (;;) { | ||
530 | done = | ||
531 | line6_midibuf_read(mb, line6->buffer_message, | ||
532 | LINE6_MESSAGE_MAXLEN); | ||
533 | |||
534 | if (done == 0) | ||
535 | break; | ||
536 | |||
537 | line6->message_length = done; | ||
538 | line6_midi_receive(line6, line6->buffer_message, done); | ||
539 | |||
540 | if (line6->process_message) | ||
541 | line6->process_message(line6); | ||
542 | } | ||
543 | |||
544 | line6_start_listen(line6); | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | Send channel number (i.e., switch to a different sound). | ||
549 | */ | ||
550 | int line6_send_program(struct usb_line6 *line6, u8 value) | ||
551 | { | ||
552 | int retval; | ||
553 | unsigned char *buffer; | ||
554 | int partial; | ||
555 | |||
556 | buffer = kmalloc(2, GFP_KERNEL); | ||
557 | if (!buffer) | ||
558 | return -ENOMEM; | ||
559 | |||
560 | buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST; | ||
561 | buffer[1] = value; | ||
562 | |||
563 | retval = usb_interrupt_msg(line6->usbdev, | ||
564 | usb_sndintpipe(line6->usbdev, | ||
565 | line6->properties->ep_ctrl_w), | ||
566 | buffer, 2, &partial, LINE6_TIMEOUT * HZ); | ||
567 | |||
568 | if (retval) | ||
569 | dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", | ||
570 | retval); | ||
571 | |||
572 | kfree(buffer); | ||
573 | return retval; | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | Transmit Line6 control parameter. | ||
578 | */ | ||
579 | int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) | ||
580 | { | ||
581 | int retval; | ||
582 | unsigned char *buffer; | ||
583 | int partial; | ||
584 | |||
585 | buffer = kmalloc(3, GFP_KERNEL); | ||
586 | if (!buffer) | ||
587 | return -ENOMEM; | ||
588 | |||
589 | buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST; | ||
590 | buffer[1] = param; | ||
591 | buffer[2] = value; | ||
592 | |||
593 | retval = usb_interrupt_msg(line6->usbdev, | ||
594 | usb_sndintpipe(line6->usbdev, | ||
595 | line6->properties->ep_ctrl_w), | ||
596 | buffer, 3, &partial, LINE6_TIMEOUT * HZ); | ||
597 | |||
598 | if (retval) | ||
599 | dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", | ||
600 | retval); | ||
601 | |||
602 | kfree(buffer); | ||
603 | return retval; | ||
604 | } | ||
605 | |||
606 | /* | ||
607 | Read data from device. | ||
608 | */ | ||
609 | int line6_read_data(struct usb_line6 *line6, int address, void *data, | ||
610 | size_t datalen) | ||
611 | { | ||
612 | struct usb_device *usbdev = line6->usbdev; | ||
613 | int ret; | ||
614 | unsigned char len; | ||
615 | |||
616 | /* query the serial number: */ | ||
617 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | ||
618 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
619 | (datalen << 8) | 0x21, address, | ||
620 | NULL, 0, LINE6_TIMEOUT * HZ); | ||
621 | |||
622 | if (ret < 0) { | ||
623 | dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | /* Wait for data length. We'll get 0xff until length arrives. */ | ||
628 | do { | ||
629 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | ||
630 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | ||
631 | USB_DIR_IN, | ||
632 | 0x0012, 0x0000, &len, 1, | ||
633 | LINE6_TIMEOUT * HZ); | ||
634 | if (ret < 0) { | ||
635 | dev_err(line6->ifcdev, | ||
636 | "receive length failed (error %d)\n", ret); | ||
637 | return ret; | ||
638 | } | ||
639 | } while (len == 0xff); | ||
640 | |||
641 | if (len != datalen) { | ||
642 | /* should be equal or something went wrong */ | ||
643 | dev_err(line6->ifcdev, | ||
644 | "length mismatch (expected %d, got %d)\n", | ||
645 | (int)datalen, (int)len); | ||
646 | return -EINVAL; | ||
647 | } | ||
648 | |||
649 | /* receive the result: */ | ||
650 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | ||
651 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
652 | 0x0013, 0x0000, data, datalen, | ||
653 | LINE6_TIMEOUT * HZ); | ||
654 | |||
655 | if (ret < 0) { | ||
656 | dev_err(line6->ifcdev, "read failed (error %d)\n", ret); | ||
657 | return ret; | ||
658 | } | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | /* | ||
664 | Write data to device. | ||
665 | */ | ||
666 | int line6_write_data(struct usb_line6 *line6, int address, void *data, | ||
667 | size_t datalen) | ||
668 | { | ||
669 | struct usb_device *usbdev = line6->usbdev; | ||
670 | int ret; | ||
671 | unsigned char status; | ||
672 | |||
673 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | ||
674 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
675 | 0x0022, address, data, datalen, | ||
676 | LINE6_TIMEOUT * HZ); | ||
677 | |||
678 | if (ret < 0) { | ||
679 | dev_err(line6->ifcdev, | ||
680 | "write request failed (error %d)\n", ret); | ||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | do { | ||
685 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), | ||
686 | 0x67, | ||
687 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | ||
688 | USB_DIR_IN, | ||
689 | 0x0012, 0x0000, | ||
690 | &status, 1, LINE6_TIMEOUT * HZ); | ||
691 | |||
692 | if (ret < 0) { | ||
693 | dev_err(line6->ifcdev, | ||
694 | "receiving status failed (error %d)\n", ret); | ||
695 | return ret; | ||
696 | } | ||
697 | } while (status == 0xff); | ||
698 | |||
699 | if (status != 0) { | ||
700 | dev_err(line6->ifcdev, "write failed (error %d)\n", ret); | ||
701 | return -EINVAL; | ||
702 | } | ||
703 | |||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | Read Line6 device serial number. | ||
709 | (POD, TonePort, GuitarPort) | ||
710 | */ | ||
711 | int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) | ||
712 | { | ||
713 | return line6_read_data(line6, 0x80d0, serial_number, | ||
714 | sizeof(*serial_number)); | ||
715 | } | ||
716 | |||
717 | /* | ||
718 | No operation (i.e., unsupported). | ||
719 | */ | ||
720 | ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, | ||
721 | char *buf) | ||
722 | { | ||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | Generic destructor. | ||
728 | */ | ||
729 | static void line6_destruct(struct usb_interface *interface) | ||
730 | { | ||
731 | struct usb_line6 *line6; | ||
732 | |||
733 | if (interface == NULL) | ||
734 | return; | ||
735 | line6 = usb_get_intfdata(interface); | ||
736 | if (line6 == NULL) | ||
737 | return; | ||
738 | |||
739 | /* free buffer memory first: */ | ||
740 | kfree(line6->buffer_message); | ||
741 | kfree(line6->buffer_listen); | ||
742 | |||
743 | /* then free URBs: */ | ||
744 | usb_free_urb(line6->urb_listen); | ||
745 | |||
746 | /* make sure the device isn't destructed twice: */ | ||
747 | usb_set_intfdata(interface, NULL); | ||
748 | |||
749 | /* free interface data: */ | ||
750 | kfree(line6); | ||
751 | } | ||
752 | |||
753 | /* | ||
754 | Probe USB device. | ||
755 | */ | ||
756 | static int line6_probe(struct usb_interface *interface, | ||
757 | const struct usb_device_id *id) | ||
758 | { | ||
759 | enum line6_device_type devtype; | ||
760 | struct usb_device *usbdev; | ||
761 | struct usb_line6 *line6; | ||
762 | const struct line6_properties *properties; | ||
763 | int interface_number; | ||
764 | int size = 0; | ||
765 | int ret; | ||
766 | |||
767 | if (interface == NULL) | ||
768 | return -ENODEV; | ||
769 | usbdev = interface_to_usbdev(interface); | ||
770 | if (usbdev == NULL) | ||
771 | return -ENODEV; | ||
772 | |||
773 | /* we don't handle multiple configurations */ | ||
774 | if (usbdev->descriptor.bNumConfigurations != 1) { | ||
775 | ret = -ENODEV; | ||
776 | goto err_put; | ||
777 | } | ||
778 | |||
779 | devtype = id->driver_info; | ||
780 | |||
781 | /* initialize device info: */ | ||
782 | properties = &line6_properties_table[devtype]; | ||
783 | dev_info(&interface->dev, "Line6 %s found\n", properties->name); | ||
784 | |||
785 | /* query interface number */ | ||
786 | interface_number = interface->cur_altsetting->desc.bInterfaceNumber; | ||
787 | |||
788 | ret = usb_set_interface(usbdev, interface_number, | ||
789 | properties->altsetting); | ||
790 | if (ret < 0) { | ||
791 | dev_err(&interface->dev, "set_interface failed\n"); | ||
792 | goto err_put; | ||
793 | } | ||
794 | |||
795 | /* initialize device data based on device: */ | ||
796 | switch (devtype) { | ||
797 | case LINE6_BASSPODXT: | ||
798 | case LINE6_BASSPODXTLIVE: | ||
799 | case LINE6_BASSPODXTPRO: | ||
800 | case LINE6_PODXT: | ||
801 | case LINE6_PODXTPRO: | ||
802 | size = sizeof(struct usb_line6_pod); | ||
803 | break; | ||
804 | |||
805 | case LINE6_PODHD300: | ||
806 | case LINE6_PODHD400: | ||
807 | size = sizeof(struct usb_line6_podhd); | ||
808 | break; | ||
809 | |||
810 | case LINE6_PODHD500_0: | ||
811 | case LINE6_PODHD500_1: | ||
812 | size = sizeof(struct usb_line6_podhd); | ||
813 | break; | ||
814 | |||
815 | case LINE6_POCKETPOD: | ||
816 | size = sizeof(struct usb_line6_pod); | ||
817 | break; | ||
818 | |||
819 | case LINE6_PODSTUDIO_GX: | ||
820 | case LINE6_PODSTUDIO_UX1: | ||
821 | case LINE6_PODSTUDIO_UX2: | ||
822 | case LINE6_TONEPORT_GX: | ||
823 | case LINE6_TONEPORT_UX1: | ||
824 | case LINE6_TONEPORT_UX2: | ||
825 | case LINE6_GUITARPORT: | ||
826 | size = sizeof(struct usb_line6_toneport); | ||
827 | break; | ||
828 | |||
829 | case LINE6_PODXTLIVE_POD: | ||
830 | size = sizeof(struct usb_line6_pod); | ||
831 | break; | ||
832 | |||
833 | case LINE6_PODXTLIVE_VARIAX: | ||
834 | size = sizeof(struct usb_line6_variax); | ||
835 | break; | ||
836 | |||
837 | case LINE6_VARIAX: | ||
838 | size = sizeof(struct usb_line6_variax); | ||
839 | break; | ||
840 | |||
841 | default: | ||
842 | MISSING_CASE; | ||
843 | ret = -ENODEV; | ||
844 | goto err_put; | ||
845 | } | ||
846 | |||
847 | if (size == 0) { | ||
848 | dev_err(&interface->dev, | ||
849 | "driver bug: interface data size not set\n"); | ||
850 | ret = -ENODEV; | ||
851 | goto err_put; | ||
852 | } | ||
853 | |||
854 | line6 = kzalloc(size, GFP_KERNEL); | ||
855 | if (line6 == NULL) { | ||
856 | ret = -ENODEV; | ||
857 | goto err_put; | ||
858 | } | ||
859 | |||
860 | /* store basic data: */ | ||
861 | line6->properties = properties; | ||
862 | line6->usbdev = usbdev; | ||
863 | line6->ifcdev = &interface->dev; | ||
864 | line6->type = devtype; | ||
865 | |||
866 | /* get data from endpoint descriptor (see usb_maxpacket): */ | ||
867 | { | ||
868 | struct usb_host_endpoint *ep; | ||
869 | unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r); | ||
870 | unsigned epnum = usb_pipeendpoint(pipe); | ||
871 | ep = usbdev->ep_in[epnum]; | ||
872 | |||
873 | if (ep != NULL) { | ||
874 | line6->interval = ep->desc.bInterval; | ||
875 | line6->max_packet_size = | ||
876 | le16_to_cpu(ep->desc.wMaxPacketSize); | ||
877 | } else { | ||
878 | line6->interval = LINE6_FALLBACK_INTERVAL; | ||
879 | line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; | ||
880 | dev_err(line6->ifcdev, | ||
881 | "endpoint not available, using fallback values"); | ||
882 | } | ||
883 | } | ||
884 | |||
885 | usb_set_intfdata(interface, line6); | ||
886 | |||
887 | if (properties->capabilities & LINE6_CAP_CONTROL) { | ||
888 | /* initialize USB buffers: */ | ||
889 | line6->buffer_listen = | ||
890 | kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); | ||
891 | if (line6->buffer_listen == NULL) { | ||
892 | ret = -ENOMEM; | ||
893 | goto err_destruct; | ||
894 | } | ||
895 | |||
896 | line6->buffer_message = | ||
897 | kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); | ||
898 | if (line6->buffer_message == NULL) { | ||
899 | ret = -ENOMEM; | ||
900 | goto err_destruct; | ||
901 | } | ||
902 | |||
903 | line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); | ||
904 | |||
905 | if (line6->urb_listen == NULL) { | ||
906 | dev_err(&interface->dev, "Out of memory\n"); | ||
907 | line6_destruct(interface); | ||
908 | ret = -ENOMEM; | ||
909 | goto err_destruct; | ||
910 | } | ||
911 | |||
912 | ret = line6_start_listen(line6); | ||
913 | if (ret < 0) { | ||
914 | dev_err(&interface->dev, "%s: usb_submit_urb failed\n", | ||
915 | __func__); | ||
916 | goto err_destruct; | ||
917 | } | ||
918 | } | ||
919 | |||
920 | /* initialize device data based on device: */ | ||
921 | switch (devtype) { | ||
922 | case LINE6_BASSPODXT: | ||
923 | case LINE6_BASSPODXTLIVE: | ||
924 | case LINE6_BASSPODXTPRO: | ||
925 | case LINE6_POCKETPOD: | ||
926 | case LINE6_PODXT: | ||
927 | case LINE6_PODXTPRO: | ||
928 | ret = line6_pod_init(interface, line6); | ||
929 | break; | ||
930 | |||
931 | case LINE6_PODHD300: | ||
932 | case LINE6_PODHD400: | ||
933 | case LINE6_PODHD500_0: | ||
934 | case LINE6_PODHD500_1: | ||
935 | ret = line6_podhd_init(interface, line6); | ||
936 | break; | ||
937 | |||
938 | case LINE6_PODXTLIVE_POD: | ||
939 | ret = line6_pod_init(interface, line6); | ||
940 | break; | ||
941 | |||
942 | case LINE6_PODXTLIVE_VARIAX: | ||
943 | ret = line6_variax_init(interface, line6); | ||
944 | break; | ||
945 | |||
946 | case LINE6_VARIAX: | ||
947 | ret = line6_variax_init(interface, line6); | ||
948 | break; | ||
949 | |||
950 | case LINE6_PODSTUDIO_GX: | ||
951 | case LINE6_PODSTUDIO_UX1: | ||
952 | case LINE6_PODSTUDIO_UX2: | ||
953 | case LINE6_TONEPORT_GX: | ||
954 | case LINE6_TONEPORT_UX1: | ||
955 | case LINE6_TONEPORT_UX2: | ||
956 | case LINE6_GUITARPORT: | ||
957 | ret = line6_toneport_init(interface, line6); | ||
958 | break; | ||
959 | |||
960 | default: | ||
961 | MISSING_CASE; | ||
962 | ret = -ENODEV; | ||
963 | } | ||
964 | |||
965 | if (ret < 0) | ||
966 | goto err_destruct; | ||
967 | |||
968 | ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, | ||
969 | "usb_device"); | ||
970 | if (ret < 0) | ||
971 | goto err_destruct; | ||
972 | |||
973 | /* creation of additional special files should go here */ | ||
974 | |||
975 | dev_info(&interface->dev, "Line6 %s now attached\n", | ||
976 | line6->properties->name); | ||
977 | |||
978 | /* increment reference counters: */ | ||
979 | usb_get_intf(interface); | ||
980 | usb_get_dev(usbdev); | ||
981 | |||
982 | return 0; | ||
983 | |||
984 | err_destruct: | ||
985 | line6_destruct(interface); | ||
986 | err_put: | ||
987 | return ret; | ||
988 | } | ||
989 | |||
990 | /* | ||
991 | Line6 device disconnected. | ||
992 | */ | ||
993 | static void line6_disconnect(struct usb_interface *interface) | ||
994 | { | ||
995 | struct usb_line6 *line6; | ||
996 | struct usb_device *usbdev; | ||
997 | int interface_number; | ||
998 | |||
999 | if (interface == NULL) | ||
1000 | return; | ||
1001 | usbdev = interface_to_usbdev(interface); | ||
1002 | if (usbdev == NULL) | ||
1003 | return; | ||
1004 | |||
1005 | /* removal of additional special files should go here */ | ||
1006 | |||
1007 | sysfs_remove_link(&interface->dev.kobj, "usb_device"); | ||
1008 | |||
1009 | interface_number = interface->cur_altsetting->desc.bInterfaceNumber; | ||
1010 | line6 = usb_get_intfdata(interface); | ||
1011 | |||
1012 | if (line6 != NULL) { | ||
1013 | if (line6->urb_listen != NULL) | ||
1014 | line6_stop_listen(line6); | ||
1015 | |||
1016 | if (usbdev != line6->usbdev) | ||
1017 | dev_err(line6->ifcdev, | ||
1018 | "driver bug: inconsistent usb device\n"); | ||
1019 | |||
1020 | line6->disconnect(interface); | ||
1021 | |||
1022 | dev_info(&interface->dev, "Line6 %s now disconnected\n", | ||
1023 | line6->properties->name); | ||
1024 | } | ||
1025 | |||
1026 | line6_destruct(interface); | ||
1027 | |||
1028 | /* decrement reference counters: */ | ||
1029 | usb_put_intf(interface); | ||
1030 | usb_put_dev(usbdev); | ||
1031 | } | ||
1032 | |||
1033 | #ifdef CONFIG_PM | ||
1034 | |||
1035 | /* | ||
1036 | Suspend Line6 device. | ||
1037 | */ | ||
1038 | static int line6_suspend(struct usb_interface *interface, pm_message_t message) | ||
1039 | { | ||
1040 | struct usb_line6 *line6 = usb_get_intfdata(interface); | ||
1041 | struct snd_line6_pcm *line6pcm = line6->line6pcm; | ||
1042 | |||
1043 | snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); | ||
1044 | |||
1045 | if (line6->properties->capabilities & LINE6_CAP_CONTROL) | ||
1046 | line6_stop_listen(line6); | ||
1047 | |||
1048 | if (line6pcm != NULL) { | ||
1049 | snd_pcm_suspend_all(line6pcm->pcm); | ||
1050 | line6_pcm_disconnect(line6pcm); | ||
1051 | line6pcm->flags = 0; | ||
1052 | } | ||
1053 | |||
1054 | return 0; | ||
1055 | } | ||
1056 | |||
1057 | /* | ||
1058 | Resume Line6 device. | ||
1059 | */ | ||
1060 | static int line6_resume(struct usb_interface *interface) | ||
1061 | { | ||
1062 | struct usb_line6 *line6 = usb_get_intfdata(interface); | ||
1063 | |||
1064 | if (line6->properties->capabilities & LINE6_CAP_CONTROL) | ||
1065 | line6_start_listen(line6); | ||
1066 | |||
1067 | snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | /* | ||
1072 | Resume Line6 device after reset. | ||
1073 | */ | ||
1074 | static int line6_reset_resume(struct usb_interface *interface) | ||
1075 | { | ||
1076 | struct usb_line6 *line6 = usb_get_intfdata(interface); | ||
1077 | |||
1078 | switch (line6->type) { | ||
1079 | case LINE6_PODSTUDIO_GX: | ||
1080 | case LINE6_PODSTUDIO_UX1: | ||
1081 | case LINE6_PODSTUDIO_UX2: | ||
1082 | case LINE6_TONEPORT_GX: | ||
1083 | case LINE6_TONEPORT_UX1: | ||
1084 | case LINE6_TONEPORT_UX2: | ||
1085 | case LINE6_GUITARPORT: | ||
1086 | line6_toneport_reset_resume((struct usb_line6_toneport *)line6); | ||
1087 | |||
1088 | default: | ||
1089 | break; | ||
1090 | } | ||
1091 | |||
1092 | return line6_resume(interface); | ||
1093 | } | ||
1094 | |||
1095 | #endif /* CONFIG_PM */ | ||
1096 | |||
1097 | static struct usb_driver line6_driver = { | ||
1098 | .name = DRIVER_NAME, | ||
1099 | .probe = line6_probe, | ||
1100 | .disconnect = line6_disconnect, | ||
1101 | #ifdef CONFIG_PM | ||
1102 | .suspend = line6_suspend, | ||
1103 | .resume = line6_resume, | ||
1104 | .reset_resume = line6_reset_resume, | ||
1105 | #endif | ||
1106 | .id_table = line6_id_table, | ||
1107 | }; | ||
1108 | |||
1109 | module_usb_driver(line6_driver); | ||
1110 | |||
1111 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1112 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1113 | MODULE_LICENSE("GPL"); | ||
1114 | MODULE_VERSION(DRIVER_VERSION); | ||
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h new file mode 100644 index 000000000000..ad203f197e80 --- /dev/null +++ b/sound/usb/line6/driver.h | |||
@@ -0,0 +1,228 @@ | |||
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 | #ifndef DRIVER_H | ||
13 | #define DRIVER_H | ||
14 | |||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/usb.h> | ||
17 | #include <sound/core.h> | ||
18 | |||
19 | #include "midi.h" | ||
20 | |||
21 | #define DRIVER_NAME "line6usb" | ||
22 | |||
23 | enum line6_device_type { | ||
24 | LINE6_BASSPODXT, | ||
25 | LINE6_BASSPODXTLIVE, | ||
26 | LINE6_BASSPODXTPRO, | ||
27 | LINE6_GUITARPORT, | ||
28 | LINE6_POCKETPOD, | ||
29 | LINE6_PODHD300, | ||
30 | LINE6_PODHD400, | ||
31 | LINE6_PODHD500_0, | ||
32 | LINE6_PODHD500_1, | ||
33 | LINE6_PODSTUDIO_GX, | ||
34 | LINE6_PODSTUDIO_UX1, | ||
35 | LINE6_PODSTUDIO_UX2, | ||
36 | LINE6_PODXT, | ||
37 | LINE6_PODXTLIVE_POD, | ||
38 | LINE6_PODXTLIVE_VARIAX, | ||
39 | LINE6_PODXTPRO, | ||
40 | LINE6_TONEPORT_GX, | ||
41 | LINE6_TONEPORT_UX1, | ||
42 | LINE6_TONEPORT_UX2, | ||
43 | LINE6_VARIAX | ||
44 | }; | ||
45 | |||
46 | #define LINE6_TIMEOUT 1 | ||
47 | #define LINE6_BUFSIZE_LISTEN 32 | ||
48 | #define LINE6_MESSAGE_MAXLEN 256 | ||
49 | |||
50 | /* | ||
51 | Line6 MIDI control commands | ||
52 | */ | ||
53 | #define LINE6_PARAM_CHANGE 0xb0 | ||
54 | #define LINE6_PROGRAM_CHANGE 0xc0 | ||
55 | #define LINE6_SYSEX_BEGIN 0xf0 | ||
56 | #define LINE6_SYSEX_END 0xf7 | ||
57 | #define LINE6_RESET 0xff | ||
58 | |||
59 | /* | ||
60 | MIDI channel for messages initiated by the host | ||
61 | (and eventually echoed back by the device) | ||
62 | */ | ||
63 | #define LINE6_CHANNEL_HOST 0x00 | ||
64 | |||
65 | /* | ||
66 | MIDI channel for messages initiated by the device | ||
67 | */ | ||
68 | #define LINE6_CHANNEL_DEVICE 0x02 | ||
69 | |||
70 | #define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */ | ||
71 | |||
72 | #define LINE6_CHANNEL_MASK 0x0f | ||
73 | |||
74 | #define MISSING_CASE \ | ||
75 | pr_err("line6usb driver bug: missing case in %s:%d\n", \ | ||
76 | __FILE__, __LINE__) | ||
77 | |||
78 | #define CHECK_RETURN(x) \ | ||
79 | do { \ | ||
80 | err = x; \ | ||
81 | if (err < 0) \ | ||
82 | return err; \ | ||
83 | } while (0) | ||
84 | |||
85 | #define CHECK_STARTUP_PROGRESS(x, n) \ | ||
86 | do { \ | ||
87 | if ((x) >= (n)) \ | ||
88 | return; \ | ||
89 | x = (n); \ | ||
90 | } while (0) | ||
91 | |||
92 | extern const unsigned char line6_midi_id[3]; | ||
93 | |||
94 | static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; | ||
95 | static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; | ||
96 | |||
97 | /** | ||
98 | Common properties of Line6 devices. | ||
99 | */ | ||
100 | struct line6_properties { | ||
101 | /** | ||
102 | Card id string (maximum 16 characters). | ||
103 | This can be used to address the device in ALSA programs as | ||
104 | "default:CARD=<id>" | ||
105 | */ | ||
106 | const char *id; | ||
107 | |||
108 | /** | ||
109 | Card short name (maximum 32 characters). | ||
110 | */ | ||
111 | const char *name; | ||
112 | |||
113 | /** | ||
114 | Bit vector defining this device's capabilities in the | ||
115 | line6usb driver. | ||
116 | */ | ||
117 | int capabilities; | ||
118 | |||
119 | int altsetting; | ||
120 | |||
121 | unsigned ep_ctrl_r; | ||
122 | unsigned ep_ctrl_w; | ||
123 | unsigned ep_audio_r; | ||
124 | unsigned ep_audio_w; | ||
125 | }; | ||
126 | |||
127 | /** | ||
128 | Common data shared by all Line6 devices. | ||
129 | Corresponds to a pair of USB endpoints. | ||
130 | */ | ||
131 | struct usb_line6 { | ||
132 | /** | ||
133 | USB device. | ||
134 | */ | ||
135 | struct usb_device *usbdev; | ||
136 | |||
137 | /** | ||
138 | Device type. | ||
139 | */ | ||
140 | enum line6_device_type type; | ||
141 | |||
142 | /** | ||
143 | Properties. | ||
144 | */ | ||
145 | const struct line6_properties *properties; | ||
146 | |||
147 | /** | ||
148 | Interval (ms). | ||
149 | */ | ||
150 | int interval; | ||
151 | |||
152 | /** | ||
153 | Maximum size of USB packet. | ||
154 | */ | ||
155 | int max_packet_size; | ||
156 | |||
157 | /** | ||
158 | Device representing the USB interface. | ||
159 | */ | ||
160 | struct device *ifcdev; | ||
161 | |||
162 | /** | ||
163 | Line6 sound card data structure. | ||
164 | Each device has at least MIDI or PCM. | ||
165 | */ | ||
166 | struct snd_card *card; | ||
167 | |||
168 | /** | ||
169 | Line6 PCM device data structure. | ||
170 | */ | ||
171 | struct snd_line6_pcm *line6pcm; | ||
172 | |||
173 | /** | ||
174 | Line6 MIDI device data structure. | ||
175 | */ | ||
176 | struct snd_line6_midi *line6midi; | ||
177 | |||
178 | /** | ||
179 | URB for listening to PODxt Pro control endpoint. | ||
180 | */ | ||
181 | struct urb *urb_listen; | ||
182 | |||
183 | /** | ||
184 | Buffer for listening to PODxt Pro control endpoint. | ||
185 | */ | ||
186 | unsigned char *buffer_listen; | ||
187 | |||
188 | /** | ||
189 | Buffer for message to be processed. | ||
190 | */ | ||
191 | unsigned char *buffer_message; | ||
192 | |||
193 | /** | ||
194 | Length of message to be processed. | ||
195 | */ | ||
196 | int message_length; | ||
197 | |||
198 | void (*process_message)(struct usb_line6 *); | ||
199 | void (*disconnect)(struct usb_interface *); | ||
200 | }; | ||
201 | |||
202 | extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, | ||
203 | int code2, int size); | ||
204 | extern ssize_t line6_nop_read(struct device *dev, | ||
205 | struct device_attribute *attr, char *buf); | ||
206 | extern int line6_read_data(struct usb_line6 *line6, int address, void *data, | ||
207 | size_t datalen); | ||
208 | extern int line6_read_serial_number(struct usb_line6 *line6, | ||
209 | int *serial_number); | ||
210 | extern int line6_send_program(struct usb_line6 *line6, u8 value); | ||
211 | extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, | ||
212 | int size); | ||
213 | extern int line6_send_raw_message_async(struct usb_line6 *line6, | ||
214 | const char *buffer, int size); | ||
215 | extern int line6_send_sysex_message(struct usb_line6 *line6, | ||
216 | const char *buffer, int size); | ||
217 | extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, | ||
218 | const char *buf, size_t count); | ||
219 | extern void line6_start_timer(struct timer_list *timer, unsigned int msecs, | ||
220 | void (*function)(unsigned long), | ||
221 | unsigned long data); | ||
222 | extern int line6_transmit_parameter(struct usb_line6 *line6, int param, | ||
223 | u8 value); | ||
224 | extern int line6_version_request_async(struct usb_line6 *line6); | ||
225 | extern int line6_write_data(struct usb_line6 *line6, int address, void *data, | ||
226 | size_t datalen); | ||
227 | |||
228 | #endif | ||
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c new file mode 100644 index 000000000000..c9d725ae85a0 --- /dev/null +++ b/sound/usb/line6/midi.c | |||
@@ -0,0 +1,321 @@ | |||
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/usb.h> | ||
14 | #include <sound/core.h> | ||
15 | #include <sound/rawmidi.h> | ||
16 | |||
17 | #include "audio.h" | ||
18 | #include "driver.h" | ||
19 | #include "midi.h" | ||
20 | #include "pod.h" | ||
21 | #include "usbdefs.h" | ||
22 | |||
23 | #define line6_rawmidi_substream_midi(substream) \ | ||
24 | ((struct snd_line6_midi *)((substream)->rmidi->private_data)) | ||
25 | |||
26 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, | ||
27 | int length); | ||
28 | |||
29 | /* | ||
30 | Pass data received via USB to MIDI. | ||
31 | */ | ||
32 | void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, | ||
33 | int length) | ||
34 | { | ||
35 | if (line6->line6midi->substream_receive) | ||
36 | snd_rawmidi_receive(line6->line6midi->substream_receive, | ||
37 | data, length); | ||
38 | } | ||
39 | |||
40 | /* | ||
41 | Read data from MIDI buffer and transmit them via USB. | ||
42 | */ | ||
43 | static void line6_midi_transmit(struct snd_rawmidi_substream *substream) | ||
44 | { | ||
45 | struct usb_line6 *line6 = | ||
46 | line6_rawmidi_substream_midi(substream)->line6; | ||
47 | struct snd_line6_midi *line6midi = line6->line6midi; | ||
48 | struct midi_buffer *mb = &line6midi->midibuf_out; | ||
49 | unsigned long flags; | ||
50 | unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE]; | ||
51 | int req, done; | ||
52 | |||
53 | spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags); | ||
54 | |||
55 | for (;;) { | ||
56 | req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); | ||
57 | done = snd_rawmidi_transmit_peek(substream, chunk, req); | ||
58 | |||
59 | if (done == 0) | ||
60 | break; | ||
61 | |||
62 | line6_midibuf_write(mb, chunk, done); | ||
63 | snd_rawmidi_transmit_ack(substream, done); | ||
64 | } | ||
65 | |||
66 | for (;;) { | ||
67 | done = line6_midibuf_read(mb, chunk, | ||
68 | LINE6_FALLBACK_MAXPACKETSIZE); | ||
69 | |||
70 | if (done == 0) | ||
71 | break; | ||
72 | |||
73 | send_midi_async(line6, chunk, done); | ||
74 | } | ||
75 | |||
76 | spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | Notification of completion of MIDI transmission. | ||
81 | */ | ||
82 | static void midi_sent(struct urb *urb) | ||
83 | { | ||
84 | unsigned long flags; | ||
85 | int status; | ||
86 | int num; | ||
87 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; | ||
88 | |||
89 | status = urb->status; | ||
90 | kfree(urb->transfer_buffer); | ||
91 | usb_free_urb(urb); | ||
92 | |||
93 | if (status == -ESHUTDOWN) | ||
94 | return; | ||
95 | |||
96 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); | ||
97 | num = --line6->line6midi->num_active_send_urbs; | ||
98 | |||
99 | if (num == 0) { | ||
100 | line6_midi_transmit(line6->line6midi->substream_transmit); | ||
101 | num = line6->line6midi->num_active_send_urbs; | ||
102 | } | ||
103 | |||
104 | if (num == 0) | ||
105 | wake_up(&line6->line6midi->send_wait); | ||
106 | |||
107 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | Send an asynchronous MIDI message. | ||
112 | Assumes that line6->line6midi->send_urb_lock is held | ||
113 | (i.e., this function is serialized). | ||
114 | */ | ||
115 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, | ||
116 | int length) | ||
117 | { | ||
118 | struct urb *urb; | ||
119 | int retval; | ||
120 | unsigned char *transfer_buffer; | ||
121 | |||
122 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
123 | |||
124 | if (urb == NULL) { | ||
125 | dev_err(line6->ifcdev, "Out of memory\n"); | ||
126 | return -ENOMEM; | ||
127 | } | ||
128 | |||
129 | transfer_buffer = kmemdup(data, length, GFP_ATOMIC); | ||
130 | |||
131 | if (transfer_buffer == NULL) { | ||
132 | usb_free_urb(urb); | ||
133 | dev_err(line6->ifcdev, "Out of memory\n"); | ||
134 | return -ENOMEM; | ||
135 | } | ||
136 | |||
137 | usb_fill_int_urb(urb, line6->usbdev, | ||
138 | usb_sndbulkpipe(line6->usbdev, | ||
139 | line6->properties->ep_ctrl_w), | ||
140 | transfer_buffer, length, midi_sent, line6, | ||
141 | line6->interval); | ||
142 | urb->actual_length = 0; | ||
143 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
144 | |||
145 | if (retval < 0) { | ||
146 | dev_err(line6->ifcdev, "usb_submit_urb failed\n"); | ||
147 | usb_free_urb(urb); | ||
148 | return retval; | ||
149 | } | ||
150 | |||
151 | ++line6->line6midi->num_active_send_urbs; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int line6_midi_output_open(struct snd_rawmidi_substream *substream) | ||
156 | { | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int line6_midi_output_close(struct snd_rawmidi_substream *substream) | ||
161 | { | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, | ||
166 | int up) | ||
167 | { | ||
168 | unsigned long flags; | ||
169 | struct usb_line6 *line6 = | ||
170 | line6_rawmidi_substream_midi(substream)->line6; | ||
171 | |||
172 | line6->line6midi->substream_transmit = substream; | ||
173 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); | ||
174 | |||
175 | if (line6->line6midi->num_active_send_urbs == 0) | ||
176 | line6_midi_transmit(substream); | ||
177 | |||
178 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); | ||
179 | } | ||
180 | |||
181 | static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) | ||
182 | { | ||
183 | struct usb_line6 *line6 = | ||
184 | line6_rawmidi_substream_midi(substream)->line6; | ||
185 | struct snd_line6_midi *midi = line6->line6midi; | ||
186 | |||
187 | wait_event_interruptible(midi->send_wait, | ||
188 | midi->num_active_send_urbs == 0); | ||
189 | } | ||
190 | |||
191 | static int line6_midi_input_open(struct snd_rawmidi_substream *substream) | ||
192 | { | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static int line6_midi_input_close(struct snd_rawmidi_substream *substream) | ||
197 | { | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, | ||
202 | int up) | ||
203 | { | ||
204 | struct usb_line6 *line6 = | ||
205 | line6_rawmidi_substream_midi(substream)->line6; | ||
206 | |||
207 | if (up) | ||
208 | line6->line6midi->substream_receive = substream; | ||
209 | else | ||
210 | line6->line6midi->substream_receive = NULL; | ||
211 | } | ||
212 | |||
213 | static struct snd_rawmidi_ops line6_midi_output_ops = { | ||
214 | .open = line6_midi_output_open, | ||
215 | .close = line6_midi_output_close, | ||
216 | .trigger = line6_midi_output_trigger, | ||
217 | .drain = line6_midi_output_drain, | ||
218 | }; | ||
219 | |||
220 | static struct snd_rawmidi_ops line6_midi_input_ops = { | ||
221 | .open = line6_midi_input_open, | ||
222 | .close = line6_midi_input_close, | ||
223 | .trigger = line6_midi_input_trigger, | ||
224 | }; | ||
225 | |||
226 | /* | ||
227 | Cleanup the Line6 MIDI device. | ||
228 | */ | ||
229 | static void line6_cleanup_midi(struct snd_rawmidi *rmidi) | ||
230 | { | ||
231 | } | ||
232 | |||
233 | /* Create a MIDI device */ | ||
234 | static int snd_line6_new_midi(struct snd_line6_midi *line6midi) | ||
235 | { | ||
236 | struct snd_rawmidi *rmidi; | ||
237 | int err; | ||
238 | |||
239 | err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, | ||
240 | &rmidi); | ||
241 | if (err < 0) | ||
242 | return err; | ||
243 | |||
244 | rmidi->private_data = line6midi; | ||
245 | rmidi->private_free = line6_cleanup_midi; | ||
246 | strcpy(rmidi->id, line6midi->line6->properties->id); | ||
247 | strcpy(rmidi->name, line6midi->line6->properties->name); | ||
248 | |||
249 | rmidi->info_flags = | ||
250 | SNDRV_RAWMIDI_INFO_OUTPUT | | ||
251 | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
252 | |||
253 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
254 | &line6_midi_output_ops); | ||
255 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
256 | &line6_midi_input_ops); | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* MIDI device destructor */ | ||
261 | static int snd_line6_midi_free(struct snd_device *device) | ||
262 | { | ||
263 | struct snd_line6_midi *line6midi = device->device_data; | ||
264 | |||
265 | line6_midibuf_destroy(&line6midi->midibuf_in); | ||
266 | line6_midibuf_destroy(&line6midi->midibuf_out); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | Initialize the Line6 MIDI subsystem. | ||
272 | */ | ||
273 | int line6_init_midi(struct usb_line6 *line6) | ||
274 | { | ||
275 | static struct snd_device_ops midi_ops = { | ||
276 | .dev_free = snd_line6_midi_free, | ||
277 | }; | ||
278 | |||
279 | int err; | ||
280 | struct snd_line6_midi *line6midi; | ||
281 | |||
282 | if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { | ||
283 | /* skip MIDI initialization and report success */ | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); | ||
288 | |||
289 | if (line6midi == NULL) | ||
290 | return -ENOMEM; | ||
291 | |||
292 | err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); | ||
293 | if (err < 0) { | ||
294 | kfree(line6midi); | ||
295 | return err; | ||
296 | } | ||
297 | |||
298 | err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); | ||
299 | if (err < 0) { | ||
300 | kfree(line6midi->midibuf_in.buf); | ||
301 | kfree(line6midi); | ||
302 | return err; | ||
303 | } | ||
304 | |||
305 | line6midi->line6 = line6; | ||
306 | line6->line6midi = line6midi; | ||
307 | |||
308 | err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, | ||
309 | &midi_ops); | ||
310 | if (err < 0) | ||
311 | return err; | ||
312 | |||
313 | err = snd_line6_new_midi(line6midi); | ||
314 | if (err < 0) | ||
315 | return err; | ||
316 | |||
317 | init_waitqueue_head(&line6midi->send_wait); | ||
318 | spin_lock_init(&line6midi->send_urb_lock); | ||
319 | spin_lock_init(&line6midi->midi_transmit_lock); | ||
320 | return 0; | ||
321 | } | ||
diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h new file mode 100644 index 000000000000..78f903fb4d41 --- /dev/null +++ b/sound/usb/line6/midi.h | |||
@@ -0,0 +1,72 @@ | |||
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 | #ifndef MIDI_H | ||
13 | #define MIDI_H | ||
14 | |||
15 | #include <sound/rawmidi.h> | ||
16 | |||
17 | #include "midibuf.h" | ||
18 | |||
19 | #define MIDI_BUFFER_SIZE 1024 | ||
20 | |||
21 | struct snd_line6_midi { | ||
22 | /** | ||
23 | Pointer back to the Line6 driver data structure. | ||
24 | */ | ||
25 | struct usb_line6 *line6; | ||
26 | |||
27 | /** | ||
28 | MIDI substream for receiving (or NULL if not active). | ||
29 | */ | ||
30 | struct snd_rawmidi_substream *substream_receive; | ||
31 | |||
32 | /** | ||
33 | MIDI substream for transmitting (or NULL if not active). | ||
34 | */ | ||
35 | struct snd_rawmidi_substream *substream_transmit; | ||
36 | |||
37 | /** | ||
38 | Number of currently active MIDI send URBs. | ||
39 | */ | ||
40 | int num_active_send_urbs; | ||
41 | |||
42 | /** | ||
43 | Spin lock to protect updates of send_urb. | ||
44 | */ | ||
45 | spinlock_t send_urb_lock; | ||
46 | |||
47 | /** | ||
48 | Spin lock to protect MIDI buffer handling. | ||
49 | */ | ||
50 | spinlock_t midi_transmit_lock; | ||
51 | |||
52 | /** | ||
53 | Wait queue for MIDI transmission. | ||
54 | */ | ||
55 | wait_queue_head_t send_wait; | ||
56 | |||
57 | /** | ||
58 | Buffer for incoming MIDI stream. | ||
59 | */ | ||
60 | struct midi_buffer midibuf_in; | ||
61 | |||
62 | /** | ||
63 | Buffer for outgoing MIDI stream. | ||
64 | */ | ||
65 | struct midi_buffer midibuf_out; | ||
66 | }; | ||
67 | |||
68 | extern int line6_init_midi(struct usb_line6 *line6); | ||
69 | extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, | ||
70 | int length); | ||
71 | |||
72 | #endif | ||
diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c new file mode 100644 index 000000000000..1ff856989fd6 --- /dev/null +++ b/sound/usb/line6/midibuf.c | |||
@@ -0,0 +1,270 @@ | |||
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 | |||
14 | #include "midibuf.h" | ||
15 | |||
16 | static int midibuf_message_length(unsigned char code) | ||
17 | { | ||
18 | int message_length; | ||
19 | |||
20 | if (code < 0x80) | ||
21 | message_length = -1; | ||
22 | else if (code < 0xf0) { | ||
23 | static const int length[] = { 3, 3, 3, 3, 2, 2, 3 }; | ||
24 | |||
25 | message_length = length[(code >> 4) - 8]; | ||
26 | } else { | ||
27 | /* | ||
28 | Note that according to the MIDI specification 0xf2 is | ||
29 | the "Song Position Pointer", but this is used by Line6 | ||
30 | to send sysex messages to the host. | ||
31 | */ | ||
32 | static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1, | ||
33 | 1, 1, 1, -1, 1, 1 | ||
34 | }; | ||
35 | message_length = length[code & 0x0f]; | ||
36 | } | ||
37 | |||
38 | return message_length; | ||
39 | } | ||
40 | |||
41 | static int midibuf_is_empty(struct midi_buffer *this) | ||
42 | { | ||
43 | return (this->pos_read == this->pos_write) && !this->full; | ||
44 | } | ||
45 | |||
46 | static int midibuf_is_full(struct midi_buffer *this) | ||
47 | { | ||
48 | return this->full; | ||
49 | } | ||
50 | |||
51 | void line6_midibuf_reset(struct midi_buffer *this) | ||
52 | { | ||
53 | this->pos_read = this->pos_write = this->full = 0; | ||
54 | this->command_prev = -1; | ||
55 | } | ||
56 | |||
57 | int line6_midibuf_init(struct midi_buffer *this, int size, int split) | ||
58 | { | ||
59 | this->buf = kmalloc(size, GFP_KERNEL); | ||
60 | |||
61 | if (this->buf == NULL) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | this->size = size; | ||
65 | this->split = split; | ||
66 | line6_midibuf_reset(this); | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | void line6_midibuf_status(struct midi_buffer *this) | ||
71 | { | ||
72 | pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n", | ||
73 | this->size, this->split, this->pos_read, this->pos_write, | ||
74 | this->full, this->command_prev); | ||
75 | } | ||
76 | |||
77 | int line6_midibuf_bytes_free(struct midi_buffer *this) | ||
78 | { | ||
79 | return | ||
80 | midibuf_is_full(this) ? | ||
81 | 0 : | ||
82 | (this->pos_read - this->pos_write + this->size - 1) % this->size + | ||
83 | 1; | ||
84 | } | ||
85 | |||
86 | int line6_midibuf_bytes_used(struct midi_buffer *this) | ||
87 | { | ||
88 | return | ||
89 | midibuf_is_empty(this) ? | ||
90 | 0 : | ||
91 | (this->pos_write - this->pos_read + this->size - 1) % this->size + | ||
92 | 1; | ||
93 | } | ||
94 | |||
95 | int line6_midibuf_write(struct midi_buffer *this, unsigned char *data, | ||
96 | int length) | ||
97 | { | ||
98 | int bytes_free; | ||
99 | int length1, length2; | ||
100 | int skip_active_sense = 0; | ||
101 | |||
102 | if (midibuf_is_full(this) || (length <= 0)) | ||
103 | return 0; | ||
104 | |||
105 | /* skip trailing active sense */ | ||
106 | if (data[length - 1] == 0xfe) { | ||
107 | --length; | ||
108 | skip_active_sense = 1; | ||
109 | } | ||
110 | |||
111 | bytes_free = line6_midibuf_bytes_free(this); | ||
112 | |||
113 | if (length > bytes_free) | ||
114 | length = bytes_free; | ||
115 | |||
116 | if (length > 0) { | ||
117 | length1 = this->size - this->pos_write; | ||
118 | |||
119 | if (length < length1) { | ||
120 | /* no buffer wraparound */ | ||
121 | memcpy(this->buf + this->pos_write, data, length); | ||
122 | this->pos_write += length; | ||
123 | } else { | ||
124 | /* buffer wraparound */ | ||
125 | length2 = length - length1; | ||
126 | memcpy(this->buf + this->pos_write, data, length1); | ||
127 | memcpy(this->buf, data + length1, length2); | ||
128 | this->pos_write = length2; | ||
129 | } | ||
130 | |||
131 | if (this->pos_write == this->pos_read) | ||
132 | this->full = 1; | ||
133 | } | ||
134 | |||
135 | return length + skip_active_sense; | ||
136 | } | ||
137 | |||
138 | int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, | ||
139 | int length) | ||
140 | { | ||
141 | int bytes_used; | ||
142 | int length1, length2; | ||
143 | int command; | ||
144 | int midi_length; | ||
145 | int repeat = 0; | ||
146 | int i; | ||
147 | |||
148 | /* we need to be able to store at least a 3 byte MIDI message */ | ||
149 | if (length < 3) | ||
150 | return -EINVAL; | ||
151 | |||
152 | if (midibuf_is_empty(this)) | ||
153 | return 0; | ||
154 | |||
155 | bytes_used = line6_midibuf_bytes_used(this); | ||
156 | |||
157 | if (length > bytes_used) | ||
158 | length = bytes_used; | ||
159 | |||
160 | length1 = this->size - this->pos_read; | ||
161 | |||
162 | /* check MIDI command length */ | ||
163 | command = this->buf[this->pos_read]; | ||
164 | |||
165 | if (command & 0x80) { | ||
166 | midi_length = midibuf_message_length(command); | ||
167 | this->command_prev = command; | ||
168 | } else { | ||
169 | if (this->command_prev > 0) { | ||
170 | int midi_length_prev = | ||
171 | midibuf_message_length(this->command_prev); | ||
172 | |||
173 | if (midi_length_prev > 0) { | ||
174 | midi_length = midi_length_prev - 1; | ||
175 | repeat = 1; | ||
176 | } else | ||
177 | midi_length = -1; | ||
178 | } else | ||
179 | midi_length = -1; | ||
180 | } | ||
181 | |||
182 | if (midi_length < 0) { | ||
183 | /* search for end of message */ | ||
184 | if (length < length1) { | ||
185 | /* no buffer wraparound */ | ||
186 | for (i = 1; i < length; ++i) | ||
187 | if (this->buf[this->pos_read + i] & 0x80) | ||
188 | break; | ||
189 | |||
190 | midi_length = i; | ||
191 | } else { | ||
192 | /* buffer wraparound */ | ||
193 | length2 = length - length1; | ||
194 | |||
195 | for (i = 1; i < length1; ++i) | ||
196 | if (this->buf[this->pos_read + i] & 0x80) | ||
197 | break; | ||
198 | |||
199 | if (i < length1) | ||
200 | midi_length = i; | ||
201 | else { | ||
202 | for (i = 0; i < length2; ++i) | ||
203 | if (this->buf[i] & 0x80) | ||
204 | break; | ||
205 | |||
206 | midi_length = length1 + i; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | if (midi_length == length) | ||
211 | midi_length = -1; /* end of message not found */ | ||
212 | } | ||
213 | |||
214 | if (midi_length < 0) { | ||
215 | if (!this->split) | ||
216 | return 0; /* command is not yet complete */ | ||
217 | } else { | ||
218 | if (length < midi_length) | ||
219 | return 0; /* command is not yet complete */ | ||
220 | |||
221 | length = midi_length; | ||
222 | } | ||
223 | |||
224 | if (length < length1) { | ||
225 | /* no buffer wraparound */ | ||
226 | memcpy(data + repeat, this->buf + this->pos_read, length); | ||
227 | this->pos_read += length; | ||
228 | } else { | ||
229 | /* buffer wraparound */ | ||
230 | length2 = length - length1; | ||
231 | memcpy(data + repeat, this->buf + this->pos_read, length1); | ||
232 | memcpy(data + repeat + length1, this->buf, length2); | ||
233 | this->pos_read = length2; | ||
234 | } | ||
235 | |||
236 | if (repeat) | ||
237 | data[0] = this->command_prev; | ||
238 | |||
239 | this->full = 0; | ||
240 | return length + repeat; | ||
241 | } | ||
242 | |||
243 | int line6_midibuf_ignore(struct midi_buffer *this, int length) | ||
244 | { | ||
245 | int bytes_used = line6_midibuf_bytes_used(this); | ||
246 | |||
247 | if (length > bytes_used) | ||
248 | length = bytes_used; | ||
249 | |||
250 | this->pos_read = (this->pos_read + length) % this->size; | ||
251 | this->full = 0; | ||
252 | return length; | ||
253 | } | ||
254 | |||
255 | int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask) | ||
256 | { | ||
257 | int cmd = this->command_prev; | ||
258 | |||
259 | if ((cmd >= 0x80) && (cmd < 0xf0)) | ||
260 | if ((mask & (1 << (cmd & 0x0f))) == 0) | ||
261 | return 1; | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | void line6_midibuf_destroy(struct midi_buffer *this) | ||
267 | { | ||
268 | kfree(this->buf); | ||
269 | this->buf = NULL; | ||
270 | } | ||
diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h new file mode 100644 index 000000000000..707482b940e4 --- /dev/null +++ b/sound/usb/line6/midibuf.h | |||
@@ -0,0 +1,38 @@ | |||
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 | #ifndef MIDIBUF_H | ||
13 | #define MIDIBUF_H | ||
14 | |||
15 | struct midi_buffer { | ||
16 | unsigned char *buf; | ||
17 | int size; | ||
18 | int split; | ||
19 | int pos_read, pos_write; | ||
20 | int full; | ||
21 | int command_prev; | ||
22 | }; | ||
23 | |||
24 | extern int line6_midibuf_bytes_used(struct midi_buffer *mb); | ||
25 | extern int line6_midibuf_bytes_free(struct midi_buffer *mb); | ||
26 | extern void line6_midibuf_destroy(struct midi_buffer *mb); | ||
27 | extern int line6_midibuf_ignore(struct midi_buffer *mb, int length); | ||
28 | extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split); | ||
29 | extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data, | ||
30 | int length); | ||
31 | extern void line6_midibuf_reset(struct midi_buffer *mb); | ||
32 | extern int line6_midibuf_skip_message(struct midi_buffer *mb, | ||
33 | unsigned short mask); | ||
34 | extern void line6_midibuf_status(struct midi_buffer *mb); | ||
35 | extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data, | ||
36 | int length); | ||
37 | |||
38 | #endif | ||
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c new file mode 100644 index 000000000000..6d4e5cd0482c --- /dev/null +++ b/sound/usb/line6/pcm.c | |||
@@ -0,0 +1,527 @@ | |||
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 <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" | ||
20 | #include "driver.h" | ||
21 | #include "playback.h" | ||
22 | #include "pod.h" | ||
23 | |||
24 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
25 | |||
26 | static struct snd_line6_pcm *dev2pcm(struct device *dev) | ||
27 | { | ||
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 | */ | ||
37 | static ssize_t impulse_volume_show(struct device *dev, | ||
38 | struct device_attribute *attr, char *buf) | ||
39 | { | ||
40 | return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume); | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | "write" request on "impulse_volume" special file. | ||
45 | */ | ||
46 | static ssize_t impulse_volume_store(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; | ||
52 | int ret; | ||
53 | |||
54 | ret = kstrtoint(buf, 10, &value); | ||
55 | if (ret < 0) | ||
56 | return ret; | ||
57 | |||
58 | line6pcm->impulse_volume = value; | ||
59 | |||
60 | if (value > 0) | ||
61 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE); | ||
62 | else | ||
63 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE); | ||
64 | |||
65 | return count; | ||
66 | } | ||
67 | static DEVICE_ATTR_RW(impulse_volume); | ||
68 | |||
69 | /* | ||
70 | "read" request on "impulse_period" special file. | ||
71 | */ | ||
72 | static ssize_t impulse_period_show(struct device *dev, | ||
73 | struct device_attribute *attr, char *buf) | ||
74 | { | ||
75 | return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period); | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | "write" request on "impulse_period" special file. | ||
80 | */ | ||
81 | static ssize_t impulse_period_store(struct device *dev, | ||
82 | struct device_attribute *attr, | ||
83 | const char *buf, size_t count) | ||
84 | { | ||
85 | int value; | ||
86 | int ret; | ||
87 | |||
88 | ret = kstrtoint(buf, 10, &value); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | dev2pcm(dev)->impulse_period = value; | ||
93 | return count; | ||
94 | } | ||
95 | static DEVICE_ATTR_RW(impulse_period); | ||
96 | |||
97 | #endif | ||
98 | |||
99 | static bool test_flags(unsigned long flags0, unsigned long flags1, | ||
100 | unsigned long mask) | ||
101 | { | ||
102 | return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); | ||
103 | } | ||
104 | |||
105 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels) | ||
106 | { | ||
107 | unsigned long flags_old, flags_new, flags_final; | ||
108 | int err; | ||
109 | |||
110 | do { | ||
111 | flags_old = ACCESS_ONCE(line6pcm->flags); | ||
112 | flags_new = flags_old | channels; | ||
113 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | ||
114 | |||
115 | flags_final = flags_old; | ||
116 | |||
117 | line6pcm->prev_fbuf = NULL; | ||
118 | |||
119 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) { | ||
120 | /* Invoked multiple times in a row so allocate once only */ | ||
121 | if (!line6pcm->buffer_in) { | ||
122 | line6pcm->buffer_in = | ||
123 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
124 | line6pcm->max_packet_size, GFP_KERNEL); | ||
125 | if (!line6pcm->buffer_in) { | ||
126 | err = -ENOMEM; | ||
127 | goto pcm_acquire_error; | ||
128 | } | ||
129 | |||
130 | flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) { | ||
135 | /* | ||
136 | Waiting for completion of active URBs in the stop handler is | ||
137 | a bug, we therefore report an error if capturing is restarted | ||
138 | too soon. | ||
139 | */ | ||
140 | if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) { | ||
141 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | ||
142 | return -EBUSY; | ||
143 | } | ||
144 | |||
145 | line6pcm->count_in = 0; | ||
146 | line6pcm->prev_fsize = 0; | ||
147 | err = line6_submit_audio_in_all_urbs(line6pcm); | ||
148 | |||
149 | if (err < 0) | ||
150 | goto pcm_acquire_error; | ||
151 | |||
152 | flags_final |= channels & LINE6_BITS_CAPTURE_STREAM; | ||
153 | } | ||
154 | |||
155 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) { | ||
156 | /* Invoked multiple times in a row so allocate once only */ | ||
157 | if (!line6pcm->buffer_out) { | ||
158 | line6pcm->buffer_out = | ||
159 | kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
160 | line6pcm->max_packet_size, GFP_KERNEL); | ||
161 | if (!line6pcm->buffer_out) { | ||
162 | err = -ENOMEM; | ||
163 | goto pcm_acquire_error; | ||
164 | } | ||
165 | |||
166 | flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) { | ||
171 | /* | ||
172 | See comment above regarding PCM restart. | ||
173 | */ | ||
174 | if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) { | ||
175 | dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n"); | ||
176 | return -EBUSY; | ||
177 | } | ||
178 | |||
179 | line6pcm->count_out = 0; | ||
180 | err = line6_submit_audio_out_all_urbs(line6pcm); | ||
181 | |||
182 | if (err < 0) | ||
183 | goto pcm_acquire_error; | ||
184 | |||
185 | flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM; | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | |||
190 | pcm_acquire_error: | ||
191 | /* | ||
192 | If not all requested resources/streams could be obtained, release | ||
193 | those which were successfully obtained (if any). | ||
194 | */ | ||
195 | line6_pcm_release(line6pcm, flags_final & channels); | ||
196 | return err; | ||
197 | } | ||
198 | |||
199 | int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels) | ||
200 | { | ||
201 | unsigned long flags_old, flags_new; | ||
202 | |||
203 | do { | ||
204 | flags_old = ACCESS_ONCE(line6pcm->flags); | ||
205 | flags_new = flags_old & ~channels; | ||
206 | } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old); | ||
207 | |||
208 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM)) | ||
209 | line6_unlink_audio_in_urbs(line6pcm); | ||
210 | |||
211 | if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) { | ||
212 | line6_wait_clear_audio_in_urbs(line6pcm); | ||
213 | line6_free_capture_buffer(line6pcm); | ||
214 | } | ||
215 | |||
216 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM)) | ||
217 | line6_unlink_audio_out_urbs(line6pcm); | ||
218 | |||
219 | if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) { | ||
220 | line6_wait_clear_audio_out_urbs(line6pcm); | ||
221 | line6_free_playback_buffer(line6pcm); | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* trigger callback */ | ||
228 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) | ||
229 | { | ||
230 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
231 | struct snd_pcm_substream *s; | ||
232 | int err; | ||
233 | unsigned long flags; | ||
234 | |||
235 | spin_lock_irqsave(&line6pcm->lock_trigger, flags); | ||
236 | clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags); | ||
237 | |||
238 | snd_pcm_group_for_each_entry(s, substream) { | ||
239 | switch (s->stream) { | ||
240 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
241 | err = snd_line6_playback_trigger(line6pcm, cmd); | ||
242 | |||
243 | if (err < 0) { | ||
244 | spin_unlock_irqrestore(&line6pcm->lock_trigger, | ||
245 | flags); | ||
246 | return err; | ||
247 | } | ||
248 | |||
249 | break; | ||
250 | |||
251 | case SNDRV_PCM_STREAM_CAPTURE: | ||
252 | err = snd_line6_capture_trigger(line6pcm, cmd); | ||
253 | |||
254 | if (err < 0) { | ||
255 | spin_unlock_irqrestore(&line6pcm->lock_trigger, | ||
256 | flags); | ||
257 | return err; | ||
258 | } | ||
259 | |||
260 | break; | ||
261 | |||
262 | default: | ||
263 | dev_err(line6pcm->line6->ifcdev, | ||
264 | "Unknown stream direction %d\n", s->stream); | ||
265 | } | ||
266 | } | ||
267 | |||
268 | spin_unlock_irqrestore(&line6pcm->lock_trigger, flags); | ||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | /* control info callback */ | ||
273 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, | ||
274 | struct snd_ctl_elem_info *uinfo) | ||
275 | { | ||
276 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
277 | uinfo->count = 2; | ||
278 | uinfo->value.integer.min = 0; | ||
279 | uinfo->value.integer.max = 256; | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* control get callback */ | ||
284 | static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, | ||
285 | struct snd_ctl_elem_value *ucontrol) | ||
286 | { | ||
287 | int i; | ||
288 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
289 | |||
290 | for (i = 2; i--;) | ||
291 | ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | /* control put callback */ | ||
297 | static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, | ||
298 | struct snd_ctl_elem_value *ucontrol) | ||
299 | { | ||
300 | int i, changed = 0; | ||
301 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
302 | |||
303 | for (i = 2; i--;) | ||
304 | if (line6pcm->volume_playback[i] != | ||
305 | ucontrol->value.integer.value[i]) { | ||
306 | line6pcm->volume_playback[i] = | ||
307 | ucontrol->value.integer.value[i]; | ||
308 | changed = 1; | ||
309 | } | ||
310 | |||
311 | return changed; | ||
312 | } | ||
313 | |||
314 | /* control definition */ | ||
315 | static struct snd_kcontrol_new line6_control_playback = { | ||
316 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
317 | .name = "PCM Playback Volume", | ||
318 | .index = 0, | ||
319 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
320 | .info = snd_line6_control_playback_info, | ||
321 | .get = snd_line6_control_playback_get, | ||
322 | .put = snd_line6_control_playback_put | ||
323 | }; | ||
324 | |||
325 | /* | ||
326 | Cleanup the PCM device. | ||
327 | */ | ||
328 | static void line6_cleanup_pcm(struct snd_pcm *pcm) | ||
329 | { | ||
330 | int i; | ||
331 | struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); | ||
332 | |||
333 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
334 | device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume); | ||
335 | device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period); | ||
336 | #endif | ||
337 | |||
338 | for (i = LINE6_ISO_BUFFERS; i--;) { | ||
339 | if (line6pcm->urb_audio_out[i]) { | ||
340 | usb_kill_urb(line6pcm->urb_audio_out[i]); | ||
341 | usb_free_urb(line6pcm->urb_audio_out[i]); | ||
342 | } | ||
343 | if (line6pcm->urb_audio_in[i]) { | ||
344 | usb_kill_urb(line6pcm->urb_audio_in[i]); | ||
345 | usb_free_urb(line6pcm->urb_audio_in[i]); | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | /* create a PCM device */ | ||
351 | static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm) | ||
352 | { | ||
353 | struct snd_pcm *pcm; | ||
354 | int err; | ||
355 | |||
356 | err = snd_pcm_new(line6pcm->line6->card, | ||
357 | (char *)line6pcm->line6->properties->name, | ||
358 | 0, 1, 1, &pcm); | ||
359 | if (err < 0) | ||
360 | return err; | ||
361 | |||
362 | pcm->private_data = line6pcm; | ||
363 | pcm->private_free = line6_cleanup_pcm; | ||
364 | line6pcm->pcm = pcm; | ||
365 | strcpy(pcm->name, line6pcm->line6->properties->name); | ||
366 | |||
367 | /* set operators */ | ||
368 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
369 | &snd_line6_playback_ops); | ||
370 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); | ||
371 | |||
372 | /* pre-allocation of buffers */ | ||
373 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
374 | snd_dma_continuous_data | ||
375 | (GFP_KERNEL), 64 * 1024, | ||
376 | 128 * 1024); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /* PCM device destructor */ | ||
382 | static int snd_line6_pcm_free(struct snd_device *device) | ||
383 | { | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* | ||
388 | Stop substream if still running. | ||
389 | */ | ||
390 | static void pcm_disconnect_substream(struct snd_pcm_substream *substream) | ||
391 | { | ||
392 | if (substream->runtime && snd_pcm_running(substream)) { | ||
393 | snd_pcm_stream_lock_irq(substream); | ||
394 | snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED); | ||
395 | snd_pcm_stream_unlock_irq(substream); | ||
396 | } | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | Stop PCM stream. | ||
401 | */ | ||
402 | void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) | ||
403 | { | ||
404 | pcm_disconnect_substream(get_substream | ||
405 | (line6pcm, SNDRV_PCM_STREAM_CAPTURE)); | ||
406 | pcm_disconnect_substream(get_substream | ||
407 | (line6pcm, SNDRV_PCM_STREAM_PLAYBACK)); | ||
408 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); | ||
409 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); | ||
410 | } | ||
411 | |||
412 | /* | ||
413 | Create and register the PCM device and mixer entries. | ||
414 | Create URBs for playback and capture. | ||
415 | */ | ||
416 | int line6_init_pcm(struct usb_line6 *line6, | ||
417 | struct line6_pcm_properties *properties) | ||
418 | { | ||
419 | static struct snd_device_ops pcm_ops = { | ||
420 | .dev_free = snd_line6_pcm_free, | ||
421 | }; | ||
422 | |||
423 | int err; | ||
424 | unsigned ep_read = line6->properties->ep_audio_r; | ||
425 | unsigned ep_write = line6->properties->ep_audio_w; | ||
426 | struct snd_line6_pcm *line6pcm; | ||
427 | |||
428 | if (!(line6->properties->capabilities & LINE6_CAP_PCM)) | ||
429 | return 0; /* skip PCM initialization and report success */ | ||
430 | |||
431 | line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); | ||
432 | |||
433 | if (line6pcm == NULL) | ||
434 | return -ENOMEM; | ||
435 | |||
436 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; | ||
437 | line6pcm->volume_monitor = 255; | ||
438 | line6pcm->line6 = line6; | ||
439 | |||
440 | /* Read and write buffers are sized identically, so choose minimum */ | ||
441 | line6pcm->max_packet_size = min( | ||
442 | usb_maxpacket(line6->usbdev, | ||
443 | usb_rcvisocpipe(line6->usbdev, ep_read), 0), | ||
444 | usb_maxpacket(line6->usbdev, | ||
445 | usb_sndisocpipe(line6->usbdev, ep_write), 1)); | ||
446 | |||
447 | line6pcm->properties = properties; | ||
448 | line6->line6pcm = line6pcm; | ||
449 | |||
450 | /* PCM device: */ | ||
451 | err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops); | ||
452 | if (err < 0) | ||
453 | return err; | ||
454 | |||
455 | err = snd_line6_new_pcm(line6pcm); | ||
456 | if (err < 0) | ||
457 | return err; | ||
458 | |||
459 | spin_lock_init(&line6pcm->lock_audio_out); | ||
460 | spin_lock_init(&line6pcm->lock_audio_in); | ||
461 | spin_lock_init(&line6pcm->lock_trigger); | ||
462 | |||
463 | err = line6_create_audio_out_urbs(line6pcm); | ||
464 | if (err < 0) | ||
465 | return err; | ||
466 | |||
467 | err = line6_create_audio_in_urbs(line6pcm); | ||
468 | if (err < 0) | ||
469 | return err; | ||
470 | |||
471 | /* mixer: */ | ||
472 | err = | ||
473 | snd_ctl_add(line6->card, | ||
474 | snd_ctl_new1(&line6_control_playback, line6pcm)); | ||
475 | if (err < 0) | ||
476 | return err; | ||
477 | |||
478 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
479 | /* impulse response test: */ | ||
480 | err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume); | ||
481 | if (err < 0) | ||
482 | return err; | ||
483 | |||
484 | err = device_create_file(line6->ifcdev, &dev_attr_impulse_period); | ||
485 | if (err < 0) | ||
486 | return err; | ||
487 | |||
488 | line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; | ||
489 | #endif | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | /* prepare pcm callback */ | ||
495 | int snd_line6_prepare(struct snd_pcm_substream *substream) | ||
496 | { | ||
497 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
498 | |||
499 | switch (substream->stream) { | ||
500 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
501 | if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0) | ||
502 | line6_unlink_wait_clear_audio_out_urbs(line6pcm); | ||
503 | |||
504 | break; | ||
505 | |||
506 | case SNDRV_PCM_STREAM_CAPTURE: | ||
507 | if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0) | ||
508 | line6_unlink_wait_clear_audio_in_urbs(line6pcm); | ||
509 | |||
510 | break; | ||
511 | |||
512 | default: | ||
513 | MISSING_CASE; | ||
514 | } | ||
515 | |||
516 | if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) { | ||
517 | line6pcm->count_out = 0; | ||
518 | line6pcm->pos_out = 0; | ||
519 | line6pcm->pos_out_done = 0; | ||
520 | line6pcm->bytes_out = 0; | ||
521 | line6pcm->count_in = 0; | ||
522 | line6pcm->pos_in_done = 0; | ||
523 | line6pcm->bytes_in = 0; | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h new file mode 100644 index 000000000000..7315e8131184 --- /dev/null +++ b/sound/usb/line6/pcm.h | |||
@@ -0,0 +1,374 @@ | |||
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 | /* | ||
13 | PCM interface to POD series devices. | ||
14 | */ | ||
15 | |||
16 | #ifndef PCM_H | ||
17 | #define PCM_H | ||
18 | |||
19 | #include <sound/pcm.h> | ||
20 | |||
21 | #include "driver.h" | ||
22 | #include "usbdefs.h" | ||
23 | |||
24 | /* number of URBs */ | ||
25 | #define LINE6_ISO_BUFFERS 2 | ||
26 | |||
27 | /* | ||
28 | number of USB frames per URB | ||
29 | The Line6 Windows driver always transmits two frames per packet, but | ||
30 | the Linux driver performs significantly better (i.e., lower latency) | ||
31 | with only one frame per packet. | ||
32 | */ | ||
33 | #define LINE6_ISO_PACKETS 1 | ||
34 | |||
35 | /* in a "full speed" device (such as the PODxt Pro) this means 1ms */ | ||
36 | #define LINE6_ISO_INTERVAL 1 | ||
37 | |||
38 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
39 | #define LINE6_IMPULSE_DEFAULT_PERIOD 100 | ||
40 | #endif | ||
41 | |||
42 | /* | ||
43 | Get substream from Line6 PCM data structure | ||
44 | */ | ||
45 | #define get_substream(line6pcm, stream) \ | ||
46 | (line6pcm->pcm->streams[stream].substream) | ||
47 | |||
48 | /* | ||
49 | PCM mode bits. | ||
50 | |||
51 | There are several features of the Line6 USB driver which require PCM | ||
52 | data to be exchanged with the device: | ||
53 | *) PCM playback and capture via ALSA | ||
54 | *) software monitoring (for devices without hardware monitoring) | ||
55 | *) optional impulse response measurement | ||
56 | However, from the device's point of view, there is just a single | ||
57 | capture and playback stream, which must be shared between these | ||
58 | subsystems. It is therefore necessary to maintain the state of the | ||
59 | subsystems with respect to PCM usage. We define several constants of | ||
60 | the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the | ||
61 | following meanings: | ||
62 | *) <subsystem> is one of | ||
63 | -) ALSA: PCM playback and capture via ALSA | ||
64 | -) MONITOR: software monitoring | ||
65 | -) IMPULSE: optional impulse response measurement | ||
66 | *) <direction> is one of | ||
67 | -) PLAYBACK: audio output (from host to device) | ||
68 | -) CAPTURE: audio input (from device to host) | ||
69 | *) <resource> is one of | ||
70 | -) BUFFER: buffer required by PCM data stream | ||
71 | -) STREAM: actual PCM data stream | ||
72 | |||
73 | The subsystems call line6_pcm_acquire() to acquire the (shared) | ||
74 | resources needed for a particular operation (e.g., allocate the buffer | ||
75 | for ALSA playback or start the capture stream for software monitoring). | ||
76 | When a resource is no longer needed, it is released by calling | ||
77 | line6_pcm_release(). Buffer allocation and stream startup are handled | ||
78 | separately to allow the ALSA kernel driver to perform them at | ||
79 | appropriate places (since the callback which starts a PCM stream is not | ||
80 | allowed to sleep). | ||
81 | */ | ||
82 | enum { | ||
83 | /* individual bit indices: */ | ||
84 | LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER, | ||
85 | LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, | ||
86 | LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER, | ||
87 | LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, | ||
88 | LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER, | ||
89 | LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, | ||
90 | LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, | ||
91 | LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, | ||
92 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
93 | LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, | ||
94 | LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, | ||
95 | LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, | ||
96 | LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, | ||
97 | #endif | ||
98 | LINE6_INDEX_PAUSE_PLAYBACK, | ||
99 | LINE6_INDEX_PREPARED, | ||
100 | |||
101 | #define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x | ||
102 | |||
103 | /* individual bit masks: */ | ||
104 | LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER), | ||
105 | LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM), | ||
106 | LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER), | ||
107 | LINE6_BIT(PCM_ALSA_CAPTURE_STREAM), | ||
108 | LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER), | ||
109 | LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), | ||
110 | LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), | ||
111 | LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), | ||
112 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
113 | LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), | ||
114 | LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), | ||
115 | LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), | ||
116 | LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), | ||
117 | #endif | ||
118 | LINE6_BIT(PAUSE_PLAYBACK), | ||
119 | LINE6_BIT(PREPARED), | ||
120 | |||
121 | /* combined bit masks (by operation): */ | ||
122 | LINE6_BITS_PCM_ALSA_BUFFER = | ||
123 | LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | | ||
124 | LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER, | ||
125 | |||
126 | LINE6_BITS_PCM_ALSA_STREAM = | ||
127 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | | ||
128 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM, | ||
129 | |||
130 | LINE6_BITS_PCM_MONITOR = | ||
131 | LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER | | ||
132 | LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM | | ||
133 | LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | | ||
134 | LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, | ||
135 | |||
136 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
137 | LINE6_BITS_PCM_IMPULSE = | ||
138 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | | ||
139 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | | ||
140 | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | | ||
141 | LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, | ||
142 | #endif | ||
143 | |||
144 | /* combined bit masks (by direction): */ | ||
145 | LINE6_BITS_PLAYBACK_BUFFER = | ||
146 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
147 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | | ||
148 | #endif | ||
149 | LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | | ||
150 | LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, | ||
151 | |||
152 | LINE6_BITS_PLAYBACK_STREAM = | ||
153 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
154 | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | | ||
155 | #endif | ||
156 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | | ||
157 | LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, | ||
158 | |||
159 | LINE6_BITS_CAPTURE_BUFFER = | ||
160 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
161 | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | | ||
162 | #endif | ||
163 | LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | | ||
164 | LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, | ||
165 | |||
166 | LINE6_BITS_CAPTURE_STREAM = | ||
167 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
168 | LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | | ||
169 | #endif | ||
170 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | | ||
171 | LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, | ||
172 | |||
173 | LINE6_BITS_STREAM = | ||
174 | LINE6_BITS_PLAYBACK_STREAM | | ||
175 | LINE6_BITS_CAPTURE_STREAM | ||
176 | }; | ||
177 | |||
178 | struct line6_pcm_properties { | ||
179 | struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw; | ||
180 | struct snd_pcm_hw_constraint_ratdens snd_line6_rates; | ||
181 | int bytes_per_frame; | ||
182 | }; | ||
183 | |||
184 | struct snd_line6_pcm { | ||
185 | /** | ||
186 | Pointer back to the Line6 driver data structure. | ||
187 | */ | ||
188 | struct usb_line6 *line6; | ||
189 | |||
190 | /** | ||
191 | Properties. | ||
192 | */ | ||
193 | struct line6_pcm_properties *properties; | ||
194 | |||
195 | /** | ||
196 | ALSA pcm stream | ||
197 | */ | ||
198 | struct snd_pcm *pcm; | ||
199 | |||
200 | /** | ||
201 | URBs for audio playback. | ||
202 | */ | ||
203 | struct urb *urb_audio_out[LINE6_ISO_BUFFERS]; | ||
204 | |||
205 | /** | ||
206 | URBs for audio capture. | ||
207 | */ | ||
208 | struct urb *urb_audio_in[LINE6_ISO_BUFFERS]; | ||
209 | |||
210 | /** | ||
211 | Temporary buffer for playback. | ||
212 | Since the packet size is not known in advance, this buffer is | ||
213 | large enough to store maximum size packets. | ||
214 | */ | ||
215 | unsigned char *buffer_out; | ||
216 | |||
217 | /** | ||
218 | Temporary buffer for capture. | ||
219 | Since the packet size is not known in advance, this buffer is | ||
220 | large enough to store maximum size packets. | ||
221 | */ | ||
222 | unsigned char *buffer_in; | ||
223 | |||
224 | /** | ||
225 | Previously captured frame (for software monitoring). | ||
226 | */ | ||
227 | unsigned char *prev_fbuf; | ||
228 | |||
229 | /** | ||
230 | Size of previously captured frame (for software monitoring). | ||
231 | */ | ||
232 | int prev_fsize; | ||
233 | |||
234 | /** | ||
235 | Free frame position in the playback buffer. | ||
236 | */ | ||
237 | snd_pcm_uframes_t pos_out; | ||
238 | |||
239 | /** | ||
240 | Count processed bytes for playback. | ||
241 | This is modulo period size (to determine when a period is | ||
242 | finished). | ||
243 | */ | ||
244 | unsigned bytes_out; | ||
245 | |||
246 | /** | ||
247 | Counter to create desired playback sample rate. | ||
248 | */ | ||
249 | unsigned count_out; | ||
250 | |||
251 | /** | ||
252 | Playback period size in bytes | ||
253 | */ | ||
254 | unsigned period_out; | ||
255 | |||
256 | /** | ||
257 | Processed frame position in the playback buffer. | ||
258 | The contents of the output ring buffer have been consumed by | ||
259 | the USB subsystem (i.e., sent to the USB device) up to this | ||
260 | position. | ||
261 | */ | ||
262 | snd_pcm_uframes_t pos_out_done; | ||
263 | |||
264 | /** | ||
265 | Count processed bytes for capture. | ||
266 | This is modulo period size (to determine when a period is | ||
267 | finished). | ||
268 | */ | ||
269 | unsigned bytes_in; | ||
270 | |||
271 | /** | ||
272 | Counter to create desired capture sample rate. | ||
273 | */ | ||
274 | unsigned count_in; | ||
275 | |||
276 | /** | ||
277 | Capture period size in bytes | ||
278 | */ | ||
279 | unsigned period_in; | ||
280 | |||
281 | /** | ||
282 | Processed frame position in the capture buffer. | ||
283 | The contents of the output ring buffer have been consumed by | ||
284 | the USB subsystem (i.e., sent to the USB device) up to this | ||
285 | position. | ||
286 | */ | ||
287 | snd_pcm_uframes_t pos_in_done; | ||
288 | |||
289 | /** | ||
290 | Bit mask of active playback URBs. | ||
291 | */ | ||
292 | unsigned long active_urb_out; | ||
293 | |||
294 | /** | ||
295 | Maximum size of USB packet. | ||
296 | */ | ||
297 | int max_packet_size; | ||
298 | |||
299 | /** | ||
300 | Bit mask of active capture URBs. | ||
301 | */ | ||
302 | unsigned long active_urb_in; | ||
303 | |||
304 | /** | ||
305 | Bit mask of playback URBs currently being unlinked. | ||
306 | */ | ||
307 | unsigned long unlink_urb_out; | ||
308 | |||
309 | /** | ||
310 | Bit mask of capture URBs currently being unlinked. | ||
311 | */ | ||
312 | unsigned long unlink_urb_in; | ||
313 | |||
314 | /** | ||
315 | Spin lock to protect updates of the playback buffer positions (not | ||
316 | contents!) | ||
317 | */ | ||
318 | spinlock_t lock_audio_out; | ||
319 | |||
320 | /** | ||
321 | Spin lock to protect updates of the capture buffer positions (not | ||
322 | contents!) | ||
323 | */ | ||
324 | spinlock_t lock_audio_in; | ||
325 | |||
326 | /** | ||
327 | Spin lock to protect trigger. | ||
328 | */ | ||
329 | spinlock_t lock_trigger; | ||
330 | |||
331 | /** | ||
332 | PCM playback volume (left and right). | ||
333 | */ | ||
334 | int volume_playback[2]; | ||
335 | |||
336 | /** | ||
337 | PCM monitor volume. | ||
338 | */ | ||
339 | int volume_monitor; | ||
340 | |||
341 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
342 | /** | ||
343 | Volume of impulse response test signal (if zero, test is disabled). | ||
344 | */ | ||
345 | int impulse_volume; | ||
346 | |||
347 | /** | ||
348 | Period of impulse response test signal. | ||
349 | */ | ||
350 | int impulse_period; | ||
351 | |||
352 | /** | ||
353 | Counter for impulse response test signal. | ||
354 | */ | ||
355 | int impulse_count; | ||
356 | #endif | ||
357 | |||
358 | /** | ||
359 | Several status bits (see LINE6_BIT_*). | ||
360 | */ | ||
361 | unsigned long flags; | ||
362 | |||
363 | int last_frame_in, last_frame_out; | ||
364 | }; | ||
365 | |||
366 | extern int line6_init_pcm(struct usb_line6 *line6, | ||
367 | struct line6_pcm_properties *properties); | ||
368 | extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); | ||
369 | extern int snd_line6_prepare(struct snd_pcm_substream *substream); | ||
370 | extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); | ||
371 | extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels); | ||
372 | extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels); | ||
373 | |||
374 | #endif | ||
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c new file mode 100644 index 000000000000..da2e3b8876b8 --- /dev/null +++ b/sound/usb/line6/playback.c | |||
@@ -0,0 +1,593 @@ | |||
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 <sound/core.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include <sound/pcm_params.h> | ||
16 | |||
17 | #include "audio.h" | ||
18 | #include "capture.h" | ||
19 | #include "driver.h" | ||
20 | #include "pcm.h" | ||
21 | #include "pod.h" | ||
22 | #include "playback.h" | ||
23 | |||
24 | /* | ||
25 | Software stereo volume control. | ||
26 | */ | ||
27 | static void change_volume(struct urb *urb_out, int volume[], | ||
28 | int bytes_per_frame) | ||
29 | { | ||
30 | int chn = 0; | ||
31 | |||
32 | if (volume[0] == 256 && volume[1] == 256) | ||
33 | return; /* maximum volume - no change */ | ||
34 | |||
35 | if (bytes_per_frame == 4) { | ||
36 | short *p, *buf_end; | ||
37 | |||
38 | p = (short *)urb_out->transfer_buffer; | ||
39 | buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); | ||
40 | |||
41 | for (; p < buf_end; ++p) { | ||
42 | *p = (*p * volume[chn & 1]) >> 8; | ||
43 | ++chn; | ||
44 | } | ||
45 | } else if (bytes_per_frame == 6) { | ||
46 | unsigned char *p, *buf_end; | ||
47 | |||
48 | p = (unsigned char *)urb_out->transfer_buffer; | ||
49 | buf_end = p + urb_out->transfer_buffer_length; | ||
50 | |||
51 | for (; p < buf_end; p += 3) { | ||
52 | int val; | ||
53 | |||
54 | val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); | ||
55 | val = (val * volume[chn & 1]) >> 8; | ||
56 | p[0] = val; | ||
57 | p[1] = val >> 8; | ||
58 | p[2] = val >> 16; | ||
59 | ++chn; | ||
60 | } | ||
61 | } | ||
62 | } | ||
63 | |||
64 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
65 | |||
66 | /* | ||
67 | Create signal for impulse response test. | ||
68 | */ | ||
69 | static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, | ||
70 | struct urb *urb_out, int bytes_per_frame) | ||
71 | { | ||
72 | int frames = urb_out->transfer_buffer_length / bytes_per_frame; | ||
73 | |||
74 | if (bytes_per_frame == 4) { | ||
75 | int i; | ||
76 | short *pi = (short *)line6pcm->prev_fbuf; | ||
77 | short *po = (short *)urb_out->transfer_buffer; | ||
78 | |||
79 | for (i = 0; i < frames; ++i) { | ||
80 | po[0] = pi[0]; | ||
81 | po[1] = 0; | ||
82 | pi += 2; | ||
83 | po += 2; | ||
84 | } | ||
85 | } else if (bytes_per_frame == 6) { | ||
86 | int i, j; | ||
87 | unsigned char *pi = line6pcm->prev_fbuf; | ||
88 | unsigned char *po = urb_out->transfer_buffer; | ||
89 | |||
90 | for (i = 0; i < frames; ++i) { | ||
91 | for (j = 0; j < bytes_per_frame / 2; ++j) | ||
92 | po[j] = pi[j]; | ||
93 | |||
94 | for (; j < bytes_per_frame; ++j) | ||
95 | po[j] = 0; | ||
96 | |||
97 | pi += bytes_per_frame; | ||
98 | po += bytes_per_frame; | ||
99 | } | ||
100 | } | ||
101 | if (--line6pcm->impulse_count <= 0) { | ||
102 | ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame - | ||
103 | 1] = | ||
104 | line6pcm->impulse_volume; | ||
105 | line6pcm->impulse_count = line6pcm->impulse_period; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | #endif | ||
110 | |||
111 | /* | ||
112 | Add signal to buffer for software monitoring. | ||
113 | */ | ||
114 | static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, | ||
115 | int volume, int bytes_per_frame) | ||
116 | { | ||
117 | if (volume == 0) | ||
118 | return; /* zero volume - no change */ | ||
119 | |||
120 | if (bytes_per_frame == 4) { | ||
121 | short *pi, *po, *buf_end; | ||
122 | |||
123 | pi = (short *)signal; | ||
124 | po = (short *)urb_out->transfer_buffer; | ||
125 | buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); | ||
126 | |||
127 | for (; po < buf_end; ++pi, ++po) | ||
128 | *po += (*pi * volume) >> 8; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | We don't need to handle devices with 6 bytes per frame here | ||
133 | since they all support hardware monitoring. | ||
134 | */ | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | Find a free URB, prepare audio data, and submit URB. | ||
139 | */ | ||
140 | static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | ||
141 | { | ||
142 | int index; | ||
143 | unsigned long flags; | ||
144 | int i, urb_size, urb_frames; | ||
145 | int ret; | ||
146 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; | ||
147 | const int frame_increment = | ||
148 | line6pcm->properties->snd_line6_rates.rats[0].num_min; | ||
149 | const int frame_factor = | ||
150 | line6pcm->properties->snd_line6_rates.rats[0].den * | ||
151 | (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); | ||
152 | struct urb *urb_out; | ||
153 | |||
154 | spin_lock_irqsave(&line6pcm->lock_audio_out, flags); | ||
155 | index = | ||
156 | find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS); | ||
157 | |||
158 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { | ||
159 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | ||
160 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); | ||
161 | return -EINVAL; | ||
162 | } | ||
163 | |||
164 | urb_out = line6pcm->urb_audio_out[index]; | ||
165 | urb_size = 0; | ||
166 | |||
167 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | ||
168 | /* compute frame size for given sampling rate */ | ||
169 | int fsize = 0; | ||
170 | struct usb_iso_packet_descriptor *fout = | ||
171 | &urb_out->iso_frame_desc[i]; | ||
172 | |||
173 | if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) | ||
174 | fsize = line6pcm->prev_fsize; | ||
175 | |||
176 | if (fsize == 0) { | ||
177 | int n; | ||
178 | |||
179 | line6pcm->count_out += frame_increment; | ||
180 | n = line6pcm->count_out / frame_factor; | ||
181 | line6pcm->count_out -= n * frame_factor; | ||
182 | fsize = n * bytes_per_frame; | ||
183 | } | ||
184 | |||
185 | fout->offset = urb_size; | ||
186 | fout->length = fsize; | ||
187 | urb_size += fsize; | ||
188 | } | ||
189 | |||
190 | if (urb_size == 0) { | ||
191 | /* can't determine URB size */ | ||
192 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | ||
193 | dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | urb_frames = urb_size / bytes_per_frame; | ||
198 | urb_out->transfer_buffer = | ||
199 | line6pcm->buffer_out + | ||
200 | index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; | ||
201 | urb_out->transfer_buffer_length = urb_size; | ||
202 | urb_out->context = line6pcm; | ||
203 | |||
204 | if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) && | ||
205 | !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) { | ||
206 | struct snd_pcm_runtime *runtime = | ||
207 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; | ||
208 | |||
209 | if (line6pcm->pos_out + urb_frames > runtime->buffer_size) { | ||
210 | /* | ||
211 | The transferred area goes over buffer boundary, | ||
212 | copy the data to the temp buffer. | ||
213 | */ | ||
214 | int len; | ||
215 | |||
216 | len = runtime->buffer_size - line6pcm->pos_out; | ||
217 | |||
218 | if (len > 0) { | ||
219 | memcpy(urb_out->transfer_buffer, | ||
220 | runtime->dma_area + | ||
221 | line6pcm->pos_out * bytes_per_frame, | ||
222 | len * bytes_per_frame); | ||
223 | memcpy(urb_out->transfer_buffer + | ||
224 | len * bytes_per_frame, runtime->dma_area, | ||
225 | (urb_frames - len) * bytes_per_frame); | ||
226 | } else | ||
227 | dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", | ||
228 | len); | ||
229 | } else { | ||
230 | memcpy(urb_out->transfer_buffer, | ||
231 | runtime->dma_area + | ||
232 | line6pcm->pos_out * bytes_per_frame, | ||
233 | urb_out->transfer_buffer_length); | ||
234 | } | ||
235 | |||
236 | line6pcm->pos_out += urb_frames; | ||
237 | if (line6pcm->pos_out >= runtime->buffer_size) | ||
238 | line6pcm->pos_out -= runtime->buffer_size; | ||
239 | } else { | ||
240 | memset(urb_out->transfer_buffer, 0, | ||
241 | urb_out->transfer_buffer_length); | ||
242 | } | ||
243 | |||
244 | change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); | ||
245 | |||
246 | if (line6pcm->prev_fbuf != NULL) { | ||
247 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
248 | if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { | ||
249 | create_impulse_test_signal(line6pcm, urb_out, | ||
250 | bytes_per_frame); | ||
251 | if (line6pcm->flags & | ||
252 | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) { | ||
253 | line6_capture_copy(line6pcm, | ||
254 | urb_out->transfer_buffer, | ||
255 | urb_out-> | ||
256 | transfer_buffer_length); | ||
257 | line6_capture_check_period(line6pcm, | ||
258 | urb_out->transfer_buffer_length); | ||
259 | } | ||
260 | } else { | ||
261 | #endif | ||
262 | if (! | ||
263 | (line6pcm->line6-> | ||
264 | properties->capabilities & LINE6_CAP_HWMON) | ||
265 | && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) | ||
266 | && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)) | ||
267 | add_monitor_signal(urb_out, line6pcm->prev_fbuf, | ||
268 | line6pcm->volume_monitor, | ||
269 | bytes_per_frame); | ||
270 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | ||
271 | } | ||
272 | #endif | ||
273 | } | ||
274 | |||
275 | ret = usb_submit_urb(urb_out, GFP_ATOMIC); | ||
276 | |||
277 | if (ret == 0) | ||
278 | set_bit(index, &line6pcm->active_urb_out); | ||
279 | else | ||
280 | dev_err(line6pcm->line6->ifcdev, | ||
281 | "URB out #%d submission failed (%d)\n", index, ret); | ||
282 | |||
283 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | /* | ||
288 | Submit all currently available playback URBs. | ||
289 | */ | ||
290 | int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) | ||
291 | { | ||
292 | int ret, i; | ||
293 | |||
294 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
295 | ret = submit_audio_out_urb(line6pcm); | ||
296 | if (ret < 0) | ||
297 | return ret; | ||
298 | } | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* | ||
304 | Unlink all currently active playback URBs. | ||
305 | */ | ||
306 | void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) | ||
307 | { | ||
308 | unsigned int i; | ||
309 | |||
310 | for (i = LINE6_ISO_BUFFERS; i--;) { | ||
311 | if (test_bit(i, &line6pcm->active_urb_out)) { | ||
312 | if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { | ||
313 | struct urb *u = line6pcm->urb_audio_out[i]; | ||
314 | |||
315 | usb_unlink_urb(u); | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | /* | ||
322 | Wait until unlinking of all currently active playback URBs has been | ||
323 | finished. | ||
324 | */ | ||
325 | void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) | ||
326 | { | ||
327 | int timeout = HZ; | ||
328 | unsigned int i; | ||
329 | int alive; | ||
330 | |||
331 | do { | ||
332 | alive = 0; | ||
333 | for (i = LINE6_ISO_BUFFERS; i--;) { | ||
334 | if (test_bit(i, &line6pcm->active_urb_out)) | ||
335 | alive++; | ||
336 | } | ||
337 | if (!alive) | ||
338 | break; | ||
339 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
340 | schedule_timeout(1); | ||
341 | } while (--timeout > 0); | ||
342 | if (alive) | ||
343 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); | ||
344 | } | ||
345 | |||
346 | /* | ||
347 | Unlink all currently active playback URBs, and wait for finishing. | ||
348 | */ | ||
349 | void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) | ||
350 | { | ||
351 | line6_unlink_audio_out_urbs(line6pcm); | ||
352 | line6_wait_clear_audio_out_urbs(line6pcm); | ||
353 | } | ||
354 | |||
355 | void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm) | ||
356 | { | ||
357 | kfree(line6pcm->buffer_out); | ||
358 | line6pcm->buffer_out = NULL; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | Callback for completed playback URB. | ||
363 | */ | ||
364 | static void audio_out_callback(struct urb *urb) | ||
365 | { | ||
366 | int i, index, length = 0, shutdown = 0; | ||
367 | unsigned long flags; | ||
368 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; | ||
369 | struct snd_pcm_substream *substream = | ||
370 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
371 | |||
372 | #if USE_CLEAR_BUFFER_WORKAROUND | ||
373 | memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); | ||
374 | #endif | ||
375 | |||
376 | line6pcm->last_frame_out = urb->start_frame; | ||
377 | |||
378 | /* find index of URB */ | ||
379 | for (index = LINE6_ISO_BUFFERS; index--;) | ||
380 | if (urb == line6pcm->urb_audio_out[index]) | ||
381 | break; | ||
382 | |||
383 | if (index < 0) | ||
384 | return; /* URB has been unlinked asynchronously */ | ||
385 | |||
386 | for (i = LINE6_ISO_PACKETS; i--;) | ||
387 | length += urb->iso_frame_desc[i].length; | ||
388 | |||
389 | spin_lock_irqsave(&line6pcm->lock_audio_out, flags); | ||
390 | |||
391 | if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) { | ||
392 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
393 | |||
394 | line6pcm->pos_out_done += | ||
395 | length / line6pcm->properties->bytes_per_frame; | ||
396 | |||
397 | if (line6pcm->pos_out_done >= runtime->buffer_size) | ||
398 | line6pcm->pos_out_done -= runtime->buffer_size; | ||
399 | } | ||
400 | |||
401 | clear_bit(index, &line6pcm->active_urb_out); | ||
402 | |||
403 | for (i = LINE6_ISO_PACKETS; i--;) | ||
404 | if (urb->iso_frame_desc[i].status == -EXDEV) { | ||
405 | shutdown = 1; | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | if (test_and_clear_bit(index, &line6pcm->unlink_urb_out)) | ||
410 | shutdown = 1; | ||
411 | |||
412 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | ||
413 | |||
414 | if (!shutdown) { | ||
415 | submit_audio_out_urb(line6pcm); | ||
416 | |||
417 | if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, | ||
418 | &line6pcm->flags)) { | ||
419 | line6pcm->bytes_out += length; | ||
420 | if (line6pcm->bytes_out >= line6pcm->period_out) { | ||
421 | line6pcm->bytes_out %= line6pcm->period_out; | ||
422 | snd_pcm_period_elapsed(substream); | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* open playback callback */ | ||
429 | static int snd_line6_playback_open(struct snd_pcm_substream *substream) | ||
430 | { | ||
431 | int err; | ||
432 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
433 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
434 | |||
435 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
436 | (&line6pcm-> | ||
437 | properties->snd_line6_rates)); | ||
438 | if (err < 0) | ||
439 | return err; | ||
440 | |||
441 | runtime->hw = line6pcm->properties->snd_line6_playback_hw; | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | /* close playback callback */ | ||
446 | static int snd_line6_playback_close(struct snd_pcm_substream *substream) | ||
447 | { | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | /* hw_params playback callback */ | ||
452 | static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, | ||
453 | struct snd_pcm_hw_params *hw_params) | ||
454 | { | ||
455 | int ret; | ||
456 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
457 | |||
458 | /* -- Florian Demski [FD] */ | ||
459 | /* don't ask me why, but this fixes the bug on my machine */ | ||
460 | if (line6pcm == NULL) { | ||
461 | if (substream->pcm == NULL) | ||
462 | return -ENOMEM; | ||
463 | if (substream->pcm->private_data == NULL) | ||
464 | return -ENOMEM; | ||
465 | substream->private_data = substream->pcm->private_data; | ||
466 | line6pcm = snd_pcm_substream_chip(substream); | ||
467 | } | ||
468 | /* -- [FD] end */ | ||
469 | |||
470 | ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); | ||
471 | |||
472 | if (ret < 0) | ||
473 | return ret; | ||
474 | |||
475 | ret = snd_pcm_lib_malloc_pages(substream, | ||
476 | params_buffer_bytes(hw_params)); | ||
477 | if (ret < 0) { | ||
478 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); | ||
479 | return ret; | ||
480 | } | ||
481 | |||
482 | line6pcm->period_out = params_period_bytes(hw_params); | ||
483 | return 0; | ||
484 | } | ||
485 | |||
486 | /* hw_free playback callback */ | ||
487 | static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) | ||
488 | { | ||
489 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
490 | |||
491 | line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER); | ||
492 | return snd_pcm_lib_free_pages(substream); | ||
493 | } | ||
494 | |||
495 | /* trigger playback callback */ | ||
496 | int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) | ||
497 | { | ||
498 | int err; | ||
499 | |||
500 | switch (cmd) { | ||
501 | case SNDRV_PCM_TRIGGER_START: | ||
502 | #ifdef CONFIG_PM | ||
503 | case SNDRV_PCM_TRIGGER_RESUME: | ||
504 | #endif | ||
505 | err = line6_pcm_acquire(line6pcm, | ||
506 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); | ||
507 | |||
508 | if (err < 0) | ||
509 | return err; | ||
510 | |||
511 | break; | ||
512 | |||
513 | case SNDRV_PCM_TRIGGER_STOP: | ||
514 | #ifdef CONFIG_PM | ||
515 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
516 | #endif | ||
517 | err = line6_pcm_release(line6pcm, | ||
518 | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); | ||
519 | |||
520 | if (err < 0) | ||
521 | return err; | ||
522 | |||
523 | break; | ||
524 | |||
525 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
526 | set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); | ||
527 | break; | ||
528 | |||
529 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
530 | clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags); | ||
531 | break; | ||
532 | |||
533 | default: | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | /* playback pointer callback */ | ||
541 | static snd_pcm_uframes_t | ||
542 | snd_line6_playback_pointer(struct snd_pcm_substream *substream) | ||
543 | { | ||
544 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
545 | |||
546 | return line6pcm->pos_out_done; | ||
547 | } | ||
548 | |||
549 | /* playback operators */ | ||
550 | struct snd_pcm_ops snd_line6_playback_ops = { | ||
551 | .open = snd_line6_playback_open, | ||
552 | .close = snd_line6_playback_close, | ||
553 | .ioctl = snd_pcm_lib_ioctl, | ||
554 | .hw_params = snd_line6_playback_hw_params, | ||
555 | .hw_free = snd_line6_playback_hw_free, | ||
556 | .prepare = snd_line6_prepare, | ||
557 | .trigger = snd_line6_trigger, | ||
558 | .pointer = snd_line6_playback_pointer, | ||
559 | }; | ||
560 | |||
561 | int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) | ||
562 | { | ||
563 | struct usb_line6 *line6 = line6pcm->line6; | ||
564 | int i; | ||
565 | |||
566 | /* create audio URBs and fill in constant values: */ | ||
567 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
568 | struct urb *urb; | ||
569 | |||
570 | /* URB for audio out: */ | ||
571 | urb = line6pcm->urb_audio_out[i] = | ||
572 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); | ||
573 | |||
574 | if (urb == NULL) { | ||
575 | dev_err(line6->ifcdev, "Out of memory\n"); | ||
576 | return -ENOMEM; | ||
577 | } | ||
578 | |||
579 | urb->dev = line6->usbdev; | ||
580 | urb->pipe = | ||
581 | usb_sndisocpipe(line6->usbdev, | ||
582 | line6->properties->ep_audio_w & | ||
583 | USB_ENDPOINT_NUMBER_MASK); | ||
584 | urb->transfer_flags = URB_ISO_ASAP; | ||
585 | urb->start_frame = -1; | ||
586 | urb->number_of_packets = LINE6_ISO_PACKETS; | ||
587 | urb->interval = LINE6_ISO_INTERVAL; | ||
588 | urb->error_count = 0; | ||
589 | urb->complete = audio_out_callback; | ||
590 | } | ||
591 | |||
592 | return 0; | ||
593 | } | ||
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h new file mode 100644 index 000000000000..743bd6f74c57 --- /dev/null +++ b/sound/usb/line6/playback.h | |||
@@ -0,0 +1,41 @@ | |||
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 | #ifndef PLAYBACK_H | ||
13 | #define PLAYBACK_H | ||
14 | |||
15 | #include <sound/pcm.h> | ||
16 | |||
17 | #include "driver.h" | ||
18 | |||
19 | /* | ||
20 | * When the TonePort is used with jack in full duplex mode and the outputs are | ||
21 | * not connected, the software monitor produces an ugly noise since everything | ||
22 | * written to the output buffer (i.e., the input signal) will be repeated in | ||
23 | * the next period (sounds like a delay effect). As a workaround, the output | ||
24 | * buffer is cleared after the data have been read, but there must be a better | ||
25 | * solution. Until one is found, this workaround can be used to fix the | ||
26 | * problem. | ||
27 | */ | ||
28 | #define USE_CLEAR_BUFFER_WORKAROUND 1 | ||
29 | |||
30 | extern struct snd_pcm_ops snd_line6_playback_ops; | ||
31 | |||
32 | extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm); | ||
33 | extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm); | ||
34 | extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); | ||
35 | extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm); | ||
36 | extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm | ||
37 | *line6pcm); | ||
38 | extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm); | ||
39 | extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd); | ||
40 | |||
41 | #endif | ||
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c new file mode 100644 index 000000000000..85a43631996e --- /dev/null +++ b/sound/usb/line6/pod.c | |||
@@ -0,0 +1,453 @@ | |||
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 | static void line6_pod_process_message(struct usb_line6 *line6) | ||
135 | { | ||
136 | struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; | ||
137 | const unsigned char *buf = pod->line6.buffer_message; | ||
138 | |||
139 | if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { | ||
140 | pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; | ||
141 | pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | | ||
142 | (int) buf[10]; | ||
143 | pod_startup3(pod); | ||
144 | return; | ||
145 | } | ||
146 | |||
147 | /* Only look for sysex messages from this device */ | ||
148 | if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && | ||
149 | buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { | ||
150 | return; | ||
151 | } | ||
152 | if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) | ||
153 | return; | ||
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 | Send system parameter (from integer). | ||
164 | */ | ||
165 | static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, | ||
166 | int code) | ||
167 | { | ||
168 | char *sysex; | ||
169 | static const int size = 5; | ||
170 | |||
171 | sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); | ||
172 | if (!sysex) | ||
173 | return -ENOMEM; | ||
174 | sysex[SYSEX_DATA_OFS] = code; | ||
175 | sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; | ||
176 | sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; | ||
177 | sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; | ||
178 | sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; | ||
179 | line6_send_sysex_message(&pod->line6, sysex, size); | ||
180 | kfree(sysex); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /* | ||
185 | "read" request on "serial_number" special file. | ||
186 | */ | ||
187 | static ssize_t serial_number_show(struct device *dev, | ||
188 | struct device_attribute *attr, char *buf) | ||
189 | { | ||
190 | struct usb_interface *interface = to_usb_interface(dev); | ||
191 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
192 | |||
193 | return sprintf(buf, "%d\n", pod->serial_number); | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | "read" request on "firmware_version" special file. | ||
198 | */ | ||
199 | static ssize_t firmware_version_show(struct device *dev, | ||
200 | struct device_attribute *attr, char *buf) | ||
201 | { | ||
202 | struct usb_interface *interface = to_usb_interface(dev); | ||
203 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
204 | |||
205 | return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, | ||
206 | pod->firmware_version % 100); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | "read" request on "device_id" special file. | ||
211 | */ | ||
212 | static ssize_t device_id_show(struct device *dev, | ||
213 | struct device_attribute *attr, char *buf) | ||
214 | { | ||
215 | struct usb_interface *interface = to_usb_interface(dev); | ||
216 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
217 | |||
218 | return sprintf(buf, "%d\n", pod->device_id); | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | POD startup procedure. | ||
223 | This is a sequence of functions with special requirements (e.g., must | ||
224 | not run immediately after initialization, must not run in interrupt | ||
225 | context). After the last one has finished, the device is ready to use. | ||
226 | */ | ||
227 | |||
228 | static void pod_startup1(struct usb_line6_pod *pod) | ||
229 | { | ||
230 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); | ||
231 | |||
232 | /* delay startup procedure: */ | ||
233 | line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, | ||
234 | (unsigned long)pod); | ||
235 | } | ||
236 | |||
237 | static void pod_startup2(unsigned long data) | ||
238 | { | ||
239 | struct usb_line6_pod *pod = (struct usb_line6_pod *)data; | ||
240 | struct usb_line6 *line6 = &pod->line6; | ||
241 | |||
242 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); | ||
243 | |||
244 | /* request firmware version: */ | ||
245 | line6_version_request_async(line6); | ||
246 | } | ||
247 | |||
248 | static void pod_startup3(struct usb_line6_pod *pod) | ||
249 | { | ||
250 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); | ||
251 | |||
252 | /* schedule work for global work queue: */ | ||
253 | schedule_work(&pod->startup_work); | ||
254 | } | ||
255 | |||
256 | static void pod_startup4(struct work_struct *work) | ||
257 | { | ||
258 | struct usb_line6_pod *pod = | ||
259 | container_of(work, struct usb_line6_pod, startup_work); | ||
260 | struct usb_line6 *line6 = &pod->line6; | ||
261 | |||
262 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); | ||
263 | |||
264 | /* serial number: */ | ||
265 | line6_read_serial_number(&pod->line6, &pod->serial_number); | ||
266 | |||
267 | /* ALSA audio interface: */ | ||
268 | line6_register_audio(line6); | ||
269 | } | ||
270 | |||
271 | /* POD special files: */ | ||
272 | static DEVICE_ATTR_RO(device_id); | ||
273 | static DEVICE_ATTR_RO(firmware_version); | ||
274 | static DEVICE_ATTR_RO(serial_number); | ||
275 | |||
276 | /* control info callback */ | ||
277 | static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, | ||
278 | struct snd_ctl_elem_info *uinfo) | ||
279 | { | ||
280 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
281 | uinfo->count = 1; | ||
282 | uinfo->value.integer.min = 0; | ||
283 | uinfo->value.integer.max = 65535; | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | /* control get callback */ | ||
288 | static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, | ||
289 | struct snd_ctl_elem_value *ucontrol) | ||
290 | { | ||
291 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
292 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; | ||
293 | |||
294 | ucontrol->value.integer.value[0] = pod->monitor_level; | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* control put callback */ | ||
299 | static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, | ||
300 | struct snd_ctl_elem_value *ucontrol) | ||
301 | { | ||
302 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
303 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; | ||
304 | |||
305 | if (ucontrol->value.integer.value[0] == pod->monitor_level) | ||
306 | return 0; | ||
307 | |||
308 | pod->monitor_level = ucontrol->value.integer.value[0]; | ||
309 | pod_set_system_param_int(pod, ucontrol->value.integer.value[0], | ||
310 | POD_MONITOR_LEVEL); | ||
311 | return 1; | ||
312 | } | ||
313 | |||
314 | /* control definition */ | ||
315 | static struct snd_kcontrol_new pod_control_monitor = { | ||
316 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
317 | .name = "Monitor Playback Volume", | ||
318 | .index = 0, | ||
319 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
320 | .info = snd_pod_control_monitor_info, | ||
321 | .get = snd_pod_control_monitor_get, | ||
322 | .put = snd_pod_control_monitor_put | ||
323 | }; | ||
324 | |||
325 | /* | ||
326 | POD destructor. | ||
327 | */ | ||
328 | static void pod_destruct(struct usb_interface *interface) | ||
329 | { | ||
330 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
331 | |||
332 | if (pod == NULL) | ||
333 | return; | ||
334 | line6_cleanup_audio(&pod->line6); | ||
335 | |||
336 | del_timer(&pod->startup_timer); | ||
337 | cancel_work_sync(&pod->startup_work); | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | POD device disconnected. | ||
342 | */ | ||
343 | static void line6_pod_disconnect(struct usb_interface *interface) | ||
344 | { | ||
345 | struct usb_line6_pod *pod; | ||
346 | |||
347 | if (interface == NULL) | ||
348 | return; | ||
349 | pod = usb_get_intfdata(interface); | ||
350 | |||
351 | if (pod != NULL) { | ||
352 | struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; | ||
353 | struct device *dev = &interface->dev; | ||
354 | |||
355 | if (line6pcm != NULL) | ||
356 | line6_pcm_disconnect(line6pcm); | ||
357 | |||
358 | if (dev != NULL) { | ||
359 | /* remove sysfs entries: */ | ||
360 | device_remove_file(dev, &dev_attr_device_id); | ||
361 | device_remove_file(dev, &dev_attr_firmware_version); | ||
362 | device_remove_file(dev, &dev_attr_serial_number); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | pod_destruct(interface); | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | Create sysfs entries. | ||
371 | */ | ||
372 | static int pod_create_files2(struct device *dev) | ||
373 | { | ||
374 | int err; | ||
375 | |||
376 | CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); | ||
377 | CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); | ||
378 | CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* | ||
383 | Try to init POD device. | ||
384 | */ | ||
385 | static int pod_try_init(struct usb_interface *interface, | ||
386 | struct usb_line6 *line6) | ||
387 | { | ||
388 | int err; | ||
389 | struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; | ||
390 | |||
391 | line6->process_message = line6_pod_process_message; | ||
392 | line6->disconnect = line6_pod_disconnect; | ||
393 | |||
394 | init_timer(&pod->startup_timer); | ||
395 | INIT_WORK(&pod->startup_work, pod_startup4); | ||
396 | |||
397 | if ((interface == NULL) || (pod == NULL)) | ||
398 | return -ENODEV; | ||
399 | |||
400 | /* create sysfs entries: */ | ||
401 | err = pod_create_files2(&interface->dev); | ||
402 | if (err < 0) | ||
403 | return err; | ||
404 | |||
405 | /* initialize audio system: */ | ||
406 | err = line6_init_audio(line6); | ||
407 | if (err < 0) | ||
408 | return err; | ||
409 | |||
410 | /* initialize MIDI subsystem: */ | ||
411 | err = line6_init_midi(line6); | ||
412 | if (err < 0) | ||
413 | return err; | ||
414 | |||
415 | /* initialize PCM subsystem: */ | ||
416 | err = line6_init_pcm(line6, &pod_pcm_properties); | ||
417 | if (err < 0) | ||
418 | return err; | ||
419 | |||
420 | /* register monitor control: */ | ||
421 | err = snd_ctl_add(line6->card, | ||
422 | snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); | ||
423 | if (err < 0) | ||
424 | return err; | ||
425 | |||
426 | /* | ||
427 | When the sound card is registered at this point, the PODxt Live | ||
428 | displays "Invalid Code Error 07", so we do it later in the event | ||
429 | handler. | ||
430 | */ | ||
431 | |||
432 | if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { | ||
433 | pod->monitor_level = POD_SYSTEM_INVALID; | ||
434 | |||
435 | /* initiate startup procedure: */ | ||
436 | pod_startup1(pod); | ||
437 | } | ||
438 | |||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | Init POD device (and clean up in case of failure). | ||
444 | */ | ||
445 | int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) | ||
446 | { | ||
447 | int err = pod_try_init(interface, line6); | ||
448 | |||
449 | if (err < 0) | ||
450 | pod_destruct(interface); | ||
451 | |||
452 | return err; | ||
453 | } | ||
diff --git a/sound/usb/line6/pod.h b/sound/usb/line6/pod.h new file mode 100644 index 000000000000..87a8f0fa9cba --- /dev/null +++ b/sound/usb/line6/pod.h | |||
@@ -0,0 +1,92 @@ | |||
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 | #ifndef POD_H | ||
13 | #define POD_H | ||
14 | |||
15 | #include <linux/interrupt.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/usb.h> | ||
18 | |||
19 | #include <sound/core.h> | ||
20 | |||
21 | #include "driver.h" | ||
22 | |||
23 | /* | ||
24 | Locate name in binary program dump | ||
25 | */ | ||
26 | #define POD_NAME_OFFSET 0 | ||
27 | #define POD_NAME_LENGTH 16 | ||
28 | |||
29 | /* | ||
30 | Other constants | ||
31 | */ | ||
32 | #define POD_CONTROL_SIZE 0x80 | ||
33 | #define POD_BUFSIZE_DUMPREQ 7 | ||
34 | #define POD_STARTUP_DELAY 1000 | ||
35 | |||
36 | /* | ||
37 | Stages of POD startup procedure | ||
38 | */ | ||
39 | enum { | ||
40 | POD_STARTUP_INIT = 1, | ||
41 | POD_STARTUP_VERSIONREQ, | ||
42 | POD_STARTUP_WORKQUEUE, | ||
43 | POD_STARTUP_SETUP, | ||
44 | POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 | ||
45 | }; | ||
46 | |||
47 | struct usb_line6_pod { | ||
48 | /** | ||
49 | Generic Line6 USB data. | ||
50 | */ | ||
51 | struct usb_line6 line6; | ||
52 | |||
53 | /** | ||
54 | Instrument monitor level. | ||
55 | */ | ||
56 | int monitor_level; | ||
57 | |||
58 | /** | ||
59 | Timer for device initializaton. | ||
60 | */ | ||
61 | struct timer_list startup_timer; | ||
62 | |||
63 | /** | ||
64 | Work handler for device initializaton. | ||
65 | */ | ||
66 | struct work_struct startup_work; | ||
67 | |||
68 | /** | ||
69 | Current progress in startup procedure. | ||
70 | */ | ||
71 | int startup_progress; | ||
72 | |||
73 | /** | ||
74 | Serial number of device. | ||
75 | */ | ||
76 | int serial_number; | ||
77 | |||
78 | /** | ||
79 | Firmware version (x 100). | ||
80 | */ | ||
81 | int firmware_version; | ||
82 | |||
83 | /** | ||
84 | Device ID. | ||
85 | */ | ||
86 | int device_id; | ||
87 | }; | ||
88 | |||
89 | extern int line6_pod_init(struct usb_interface *interface, | ||
90 | struct usb_line6 *line6); | ||
91 | |||
92 | #endif | ||
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c new file mode 100644 index 000000000000..27c5402cece8 --- /dev/null +++ b/sound/usb/line6/podhd.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * Line6 Pod HD | ||
3 | * | ||
4 | * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> | ||
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 <sound/core.h> | ||
13 | #include <sound/pcm.h> | ||
14 | |||
15 | #include "audio.h" | ||
16 | #include "driver.h" | ||
17 | #include "pcm.h" | ||
18 | #include "podhd.h" | ||
19 | |||
20 | #define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ | ||
21 | |||
22 | static struct snd_ratden podhd_ratden = { | ||
23 | .num_min = 48000, | ||
24 | .num_max = 48000, | ||
25 | .num_step = 1, | ||
26 | .den = 1, | ||
27 | }; | ||
28 | |||
29 | static struct line6_pcm_properties podhd_pcm_properties = { | ||
30 | .snd_line6_playback_hw = { | ||
31 | .info = (SNDRV_PCM_INFO_MMAP | | ||
32 | SNDRV_PCM_INFO_INTERLEAVED | | ||
33 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
34 | SNDRV_PCM_INFO_MMAP_VALID | | ||
35 | SNDRV_PCM_INFO_PAUSE | | ||
36 | #ifdef CONFIG_PM | ||
37 | SNDRV_PCM_INFO_RESUME | | ||
38 | #endif | ||
39 | SNDRV_PCM_INFO_SYNC_START), | ||
40 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
41 | .rates = SNDRV_PCM_RATE_48000, | ||
42 | .rate_min = 48000, | ||
43 | .rate_max = 48000, | ||
44 | .channels_min = 2, | ||
45 | .channels_max = 2, | ||
46 | .buffer_bytes_max = 60000, | ||
47 | .period_bytes_min = 64, | ||
48 | .period_bytes_max = 8192, | ||
49 | .periods_min = 1, | ||
50 | .periods_max = 1024}, | ||
51 | .snd_line6_capture_hw = { | ||
52 | .info = (SNDRV_PCM_INFO_MMAP | | ||
53 | SNDRV_PCM_INFO_INTERLEAVED | | ||
54 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
55 | SNDRV_PCM_INFO_MMAP_VALID | | ||
56 | #ifdef CONFIG_PM | ||
57 | SNDRV_PCM_INFO_RESUME | | ||
58 | #endif | ||
59 | SNDRV_PCM_INFO_SYNC_START), | ||
60 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
61 | .rates = SNDRV_PCM_RATE_48000, | ||
62 | .rate_min = 48000, | ||
63 | .rate_max = 48000, | ||
64 | .channels_min = 2, | ||
65 | .channels_max = 2, | ||
66 | .buffer_bytes_max = 60000, | ||
67 | .period_bytes_min = 64, | ||
68 | .period_bytes_max = 8192, | ||
69 | .periods_min = 1, | ||
70 | .periods_max = 1024}, | ||
71 | .snd_line6_rates = { | ||
72 | .nrats = 1, | ||
73 | .rats = &podhd_ratden}, | ||
74 | .bytes_per_frame = PODHD_BYTES_PER_FRAME | ||
75 | }; | ||
76 | |||
77 | /* | ||
78 | POD HD destructor. | ||
79 | */ | ||
80 | static void podhd_destruct(struct usb_interface *interface) | ||
81 | { | ||
82 | struct usb_line6_podhd *podhd = usb_get_intfdata(interface); | ||
83 | |||
84 | if (podhd == NULL) | ||
85 | return; | ||
86 | line6_cleanup_audio(&podhd->line6); | ||
87 | } | ||
88 | |||
89 | /* | ||
90 | POD HD device disconnected. | ||
91 | */ | ||
92 | static void line6_podhd_disconnect(struct usb_interface *interface) | ||
93 | { | ||
94 | struct usb_line6_podhd *podhd; | ||
95 | |||
96 | if (interface == NULL) | ||
97 | return; | ||
98 | podhd = usb_get_intfdata(interface); | ||
99 | |||
100 | if (podhd != NULL) { | ||
101 | struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm; | ||
102 | |||
103 | if (line6pcm != NULL) | ||
104 | line6_pcm_disconnect(line6pcm); | ||
105 | } | ||
106 | |||
107 | podhd_destruct(interface); | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | Try to init POD HD device. | ||
112 | */ | ||
113 | static int podhd_try_init(struct usb_interface *interface, | ||
114 | struct usb_line6_podhd *podhd) | ||
115 | { | ||
116 | int err; | ||
117 | struct usb_line6 *line6 = &podhd->line6; | ||
118 | |||
119 | if ((interface == NULL) || (podhd == NULL)) | ||
120 | return -ENODEV; | ||
121 | |||
122 | line6->disconnect = line6_podhd_disconnect; | ||
123 | |||
124 | /* initialize audio system: */ | ||
125 | err = line6_init_audio(line6); | ||
126 | if (err < 0) | ||
127 | return err; | ||
128 | |||
129 | /* initialize MIDI subsystem: */ | ||
130 | err = line6_init_midi(line6); | ||
131 | if (err < 0) | ||
132 | return err; | ||
133 | |||
134 | /* initialize PCM subsystem: */ | ||
135 | err = line6_init_pcm(line6, &podhd_pcm_properties); | ||
136 | if (err < 0) | ||
137 | return err; | ||
138 | |||
139 | /* register USB audio system: */ | ||
140 | err = line6_register_audio(line6); | ||
141 | return err; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | Init POD HD device (and clean up in case of failure). | ||
146 | */ | ||
147 | int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) | ||
148 | { | ||
149 | struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; | ||
150 | int err = podhd_try_init(interface, podhd); | ||
151 | |||
152 | if (err < 0) | ||
153 | podhd_destruct(interface); | ||
154 | |||
155 | return err; | ||
156 | } | ||
diff --git a/sound/usb/line6/podhd.h b/sound/usb/line6/podhd.h new file mode 100644 index 000000000000..a14f711f9725 --- /dev/null +++ b/sound/usb/line6/podhd.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Line6 Pod HD | ||
3 | * | ||
4 | * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> | ||
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 | #ifndef PODHD_H | ||
13 | #define PODHD_H | ||
14 | |||
15 | #include <linux/usb.h> | ||
16 | |||
17 | #include "driver.h" | ||
18 | |||
19 | struct usb_line6_podhd { | ||
20 | /** | ||
21 | Generic Line6 USB data. | ||
22 | */ | ||
23 | struct usb_line6 line6; | ||
24 | }; | ||
25 | |||
26 | extern int line6_podhd_init(struct usb_interface *interface, | ||
27 | struct usb_line6 *line6); | ||
28 | |||
29 | #endif /* PODHD_H */ | ||
diff --git a/sound/usb/line6/revision.h b/sound/usb/line6/revision.h new file mode 100644 index 000000000000..b4eee2b73831 --- /dev/null +++ b/sound/usb/line6/revision.h | |||
@@ -0,0 +1,4 @@ | |||
1 | #ifndef DRIVER_REVISION | ||
2 | /* current subversion revision */ | ||
3 | #define DRIVER_REVISION " (904)" | ||
4 | #endif | ||
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c new file mode 100644 index 000000000000..aae78d8a82d9 --- /dev/null +++ b/sound/usb/line6/toneport.c | |||
@@ -0,0 +1,465 @@ | |||
1 | /* | ||
2 | * Line6 Linux USB driver - 0.9.1beta | ||
3 | * | ||
4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) | ||
5 | * Emil Myhrman (emil.myhrman@gmail.com) | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License as | ||
9 | * published by the Free Software Foundation, version 2. | ||
10 | * | ||
11 | */ | ||
12 | |||
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 "toneport.h" | ||
21 | |||
22 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); | ||
23 | |||
24 | #define TONEPORT_PCM_DELAY 1 | ||
25 | |||
26 | static struct snd_ratden toneport_ratden = { | ||
27 | .num_min = 44100, | ||
28 | .num_max = 44100, | ||
29 | .num_step = 1, | ||
30 | .den = 1 | ||
31 | }; | ||
32 | |||
33 | static struct line6_pcm_properties toneport_pcm_properties = { | ||
34 | .snd_line6_playback_hw = { | ||
35 | .info = (SNDRV_PCM_INFO_MMAP | | ||
36 | SNDRV_PCM_INFO_INTERLEAVED | | ||
37 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
38 | SNDRV_PCM_INFO_MMAP_VALID | | ||
39 | SNDRV_PCM_INFO_PAUSE | | ||
40 | #ifdef CONFIG_PM | ||
41 | SNDRV_PCM_INFO_RESUME | | ||
42 | #endif | ||
43 | SNDRV_PCM_INFO_SYNC_START), | ||
44 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
45 | .rates = SNDRV_PCM_RATE_KNOT, | ||
46 | .rate_min = 44100, | ||
47 | .rate_max = 44100, | ||
48 | .channels_min = 2, | ||
49 | .channels_max = 2, | ||
50 | .buffer_bytes_max = 60000, | ||
51 | .period_bytes_min = 64, | ||
52 | .period_bytes_max = 8192, | ||
53 | .periods_min = 1, | ||
54 | .periods_max = 1024}, | ||
55 | .snd_line6_capture_hw = { | ||
56 | .info = (SNDRV_PCM_INFO_MMAP | | ||
57 | SNDRV_PCM_INFO_INTERLEAVED | | ||
58 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
59 | SNDRV_PCM_INFO_MMAP_VALID | | ||
60 | #ifdef CONFIG_PM | ||
61 | SNDRV_PCM_INFO_RESUME | | ||
62 | #endif | ||
63 | SNDRV_PCM_INFO_SYNC_START), | ||
64 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
65 | .rates = SNDRV_PCM_RATE_KNOT, | ||
66 | .rate_min = 44100, | ||
67 | .rate_max = 44100, | ||
68 | .channels_min = 2, | ||
69 | .channels_max = 2, | ||
70 | .buffer_bytes_max = 60000, | ||
71 | .period_bytes_min = 64, | ||
72 | .period_bytes_max = 8192, | ||
73 | .periods_min = 1, | ||
74 | .periods_max = 1024}, | ||
75 | .snd_line6_rates = { | ||
76 | .nrats = 1, | ||
77 | .rats = &toneport_ratden}, | ||
78 | .bytes_per_frame = 4 | ||
79 | }; | ||
80 | |||
81 | /* | ||
82 | For the led on Guitarport. | ||
83 | Brightness goes from 0x00 to 0x26. Set a value above this to have led | ||
84 | blink. | ||
85 | (void cmd_0x02(byte red, byte green) | ||
86 | */ | ||
87 | static int led_red = 0x00; | ||
88 | static int led_green = 0x26; | ||
89 | |||
90 | static const struct { | ||
91 | const char *name; | ||
92 | int code; | ||
93 | } toneport_source_info[] = { | ||
94 | {"Microphone", 0x0a01}, | ||
95 | {"Line", 0x0801}, | ||
96 | {"Instrument", 0x0b01}, | ||
97 | {"Inst & Mic", 0x0901} | ||
98 | }; | ||
99 | |||
100 | static bool toneport_has_led(enum line6_device_type type) | ||
101 | { | ||
102 | return | ||
103 | (type == LINE6_GUITARPORT) || | ||
104 | (type == LINE6_TONEPORT_GX); | ||
105 | /* add your device here if you are missing support for the LEDs */ | ||
106 | } | ||
107 | |||
108 | static void toneport_update_led(struct device *dev) | ||
109 | { | ||
110 | struct usb_interface *interface = to_usb_interface(dev); | ||
111 | struct usb_line6_toneport *tp = usb_get_intfdata(interface); | ||
112 | struct usb_line6 *line6; | ||
113 | |||
114 | if (!tp) | ||
115 | return; | ||
116 | |||
117 | line6 = &tp->line6; | ||
118 | if (line6) | ||
119 | toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002, | ||
120 | led_green); | ||
121 | } | ||
122 | |||
123 | static ssize_t toneport_set_led_red(struct device *dev, | ||
124 | struct device_attribute *attr, | ||
125 | const char *buf, size_t count) | ||
126 | { | ||
127 | int retval; | ||
128 | |||
129 | retval = kstrtoint(buf, 10, &led_red); | ||
130 | if (retval) | ||
131 | return retval; | ||
132 | |||
133 | toneport_update_led(dev); | ||
134 | return count; | ||
135 | } | ||
136 | |||
137 | static ssize_t toneport_set_led_green(struct device *dev, | ||
138 | struct device_attribute *attr, | ||
139 | const char *buf, size_t count) | ||
140 | { | ||
141 | int retval; | ||
142 | |||
143 | retval = kstrtoint(buf, 10, &led_green); | ||
144 | if (retval) | ||
145 | return retval; | ||
146 | |||
147 | toneport_update_led(dev); | ||
148 | return count; | ||
149 | } | ||
150 | |||
151 | static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, | ||
152 | toneport_set_led_red); | ||
153 | static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, | ||
154 | toneport_set_led_green); | ||
155 | |||
156 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) | ||
157 | { | ||
158 | int ret; | ||
159 | |||
160 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | ||
161 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
162 | cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); | ||
163 | |||
164 | if (ret < 0) { | ||
165 | dev_err(&usbdev->dev, "send failed (error %d)\n", ret); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | /* monitor info callback */ | ||
173 | static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, | ||
174 | struct snd_ctl_elem_info *uinfo) | ||
175 | { | ||
176 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
177 | uinfo->count = 1; | ||
178 | uinfo->value.integer.min = 0; | ||
179 | uinfo->value.integer.max = 256; | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | /* monitor get callback */ | ||
184 | static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, | ||
185 | struct snd_ctl_elem_value *ucontrol) | ||
186 | { | ||
187 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
188 | |||
189 | ucontrol->value.integer.value[0] = line6pcm->volume_monitor; | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* monitor put callback */ | ||
194 | static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, | ||
195 | struct snd_ctl_elem_value *ucontrol) | ||
196 | { | ||
197 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
198 | |||
199 | if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) | ||
200 | return 0; | ||
201 | |||
202 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; | ||
203 | |||
204 | if (line6pcm->volume_monitor > 0) | ||
205 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); | ||
206 | else | ||
207 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); | ||
208 | |||
209 | return 1; | ||
210 | } | ||
211 | |||
212 | /* source info callback */ | ||
213 | static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, | ||
214 | struct snd_ctl_elem_info *uinfo) | ||
215 | { | ||
216 | const int size = ARRAY_SIZE(toneport_source_info); | ||
217 | |||
218 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
219 | uinfo->count = 1; | ||
220 | uinfo->value.enumerated.items = size; | ||
221 | |||
222 | if (uinfo->value.enumerated.item >= size) | ||
223 | uinfo->value.enumerated.item = size - 1; | ||
224 | |||
225 | strcpy(uinfo->value.enumerated.name, | ||
226 | toneport_source_info[uinfo->value.enumerated.item].name); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | /* source get callback */ | ||
232 | static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, | ||
233 | struct snd_ctl_elem_value *ucontrol) | ||
234 | { | ||
235 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
236 | struct usb_line6_toneport *toneport = | ||
237 | (struct usb_line6_toneport *)line6pcm->line6; | ||
238 | ucontrol->value.enumerated.item[0] = toneport->source; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | /* source put callback */ | ||
243 | static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, | ||
244 | struct snd_ctl_elem_value *ucontrol) | ||
245 | { | ||
246 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
247 | struct usb_line6_toneport *toneport = | ||
248 | (struct usb_line6_toneport *)line6pcm->line6; | ||
249 | unsigned int source; | ||
250 | |||
251 | source = ucontrol->value.enumerated.item[0]; | ||
252 | if (source >= ARRAY_SIZE(toneport_source_info)) | ||
253 | return -EINVAL; | ||
254 | if (source == toneport->source) | ||
255 | return 0; | ||
256 | |||
257 | toneport->source = source; | ||
258 | toneport_send_cmd(toneport->line6.usbdev, | ||
259 | toneport_source_info[source].code, 0x0000); | ||
260 | return 1; | ||
261 | } | ||
262 | |||
263 | static void toneport_start_pcm(unsigned long arg) | ||
264 | { | ||
265 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; | ||
266 | struct usb_line6 *line6 = &toneport->line6; | ||
267 | |||
268 | line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); | ||
269 | } | ||
270 | |||
271 | /* control definition */ | ||
272 | static struct snd_kcontrol_new toneport_control_monitor = { | ||
273 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
274 | .name = "Monitor Playback Volume", | ||
275 | .index = 0, | ||
276 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
277 | .info = snd_toneport_monitor_info, | ||
278 | .get = snd_toneport_monitor_get, | ||
279 | .put = snd_toneport_monitor_put | ||
280 | }; | ||
281 | |||
282 | /* source selector definition */ | ||
283 | static struct snd_kcontrol_new toneport_control_source = { | ||
284 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
285 | .name = "PCM Capture Source", | ||
286 | .index = 0, | ||
287 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
288 | .info = snd_toneport_source_info, | ||
289 | .get = snd_toneport_source_get, | ||
290 | .put = snd_toneport_source_put | ||
291 | }; | ||
292 | |||
293 | /* | ||
294 | Toneport destructor. | ||
295 | */ | ||
296 | static void toneport_destruct(struct usb_interface *interface) | ||
297 | { | ||
298 | struct usb_line6_toneport *toneport = usb_get_intfdata(interface); | ||
299 | |||
300 | if (toneport == NULL) | ||
301 | return; | ||
302 | line6_cleanup_audio(&toneport->line6); | ||
303 | } | ||
304 | |||
305 | /* | ||
306 | Setup Toneport device. | ||
307 | */ | ||
308 | static void toneport_setup(struct usb_line6_toneport *toneport) | ||
309 | { | ||
310 | int ticks; | ||
311 | struct usb_line6 *line6 = &toneport->line6; | ||
312 | struct usb_device *usbdev = line6->usbdev; | ||
313 | |||
314 | /* sync time on device with host: */ | ||
315 | ticks = (int)get_seconds(); | ||
316 | line6_write_data(line6, 0x80c6, &ticks, 4); | ||
317 | |||
318 | /* enable device: */ | ||
319 | toneport_send_cmd(usbdev, 0x0301, 0x0000); | ||
320 | |||
321 | /* initialize source select: */ | ||
322 | switch (line6->type) { | ||
323 | case LINE6_TONEPORT_UX1: | ||
324 | case LINE6_TONEPORT_UX2: | ||
325 | case LINE6_PODSTUDIO_UX1: | ||
326 | case LINE6_PODSTUDIO_UX2: | ||
327 | toneport_send_cmd(usbdev, | ||
328 | toneport_source_info[toneport->source].code, | ||
329 | 0x0000); | ||
330 | default: | ||
331 | break; | ||
332 | } | ||
333 | |||
334 | if (toneport_has_led(line6->type)) | ||
335 | toneport_update_led(&usbdev->dev); | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | Toneport device disconnected. | ||
340 | */ | ||
341 | static void line6_toneport_disconnect(struct usb_interface *interface) | ||
342 | { | ||
343 | struct usb_line6_toneport *toneport; | ||
344 | u16 idProduct; | ||
345 | |||
346 | if (interface == NULL) | ||
347 | return; | ||
348 | |||
349 | toneport = usb_get_intfdata(interface); | ||
350 | del_timer_sync(&toneport->timer); | ||
351 | idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); | ||
352 | |||
353 | if (toneport_has_led(idProduct)) { | ||
354 | device_remove_file(&interface->dev, &dev_attr_led_red); | ||
355 | device_remove_file(&interface->dev, &dev_attr_led_green); | ||
356 | } | ||
357 | |||
358 | if (toneport != NULL) { | ||
359 | struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; | ||
360 | |||
361 | if (line6pcm != NULL) { | ||
362 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); | ||
363 | line6_pcm_disconnect(line6pcm); | ||
364 | } | ||
365 | } | ||
366 | |||
367 | toneport_destruct(interface); | ||
368 | } | ||
369 | |||
370 | |||
371 | /* | ||
372 | Try to init Toneport device. | ||
373 | */ | ||
374 | static int toneport_try_init(struct usb_interface *interface, | ||
375 | struct usb_line6 *line6) | ||
376 | { | ||
377 | int err; | ||
378 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; | ||
379 | |||
380 | if ((interface == NULL) || (toneport == NULL)) | ||
381 | return -ENODEV; | ||
382 | |||
383 | line6->disconnect = line6_toneport_disconnect; | ||
384 | |||
385 | /* initialize audio system: */ | ||
386 | err = line6_init_audio(line6); | ||
387 | if (err < 0) | ||
388 | return err; | ||
389 | |||
390 | /* initialize PCM subsystem: */ | ||
391 | err = line6_init_pcm(line6, &toneport_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(&toneport_control_monitor, | ||
398 | line6->line6pcm)); | ||
399 | if (err < 0) | ||
400 | return err; | ||
401 | |||
402 | /* register source select control: */ | ||
403 | switch (line6->type) { | ||
404 | case LINE6_TONEPORT_UX1: | ||
405 | case LINE6_TONEPORT_UX2: | ||
406 | case LINE6_PODSTUDIO_UX1: | ||
407 | case LINE6_PODSTUDIO_UX2: | ||
408 | err = | ||
409 | snd_ctl_add(line6->card, | ||
410 | snd_ctl_new1(&toneport_control_source, | ||
411 | line6->line6pcm)); | ||
412 | if (err < 0) | ||
413 | return err; | ||
414 | |||
415 | default: | ||
416 | break; | ||
417 | } | ||
418 | |||
419 | /* register audio system: */ | ||
420 | err = line6_register_audio(line6); | ||
421 | if (err < 0) | ||
422 | return err; | ||
423 | |||
424 | line6_read_serial_number(line6, &toneport->serial_number); | ||
425 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); | ||
426 | |||
427 | if (toneport_has_led(line6->type)) { | ||
428 | CHECK_RETURN(device_create_file | ||
429 | (&interface->dev, &dev_attr_led_red)); | ||
430 | CHECK_RETURN(device_create_file | ||
431 | (&interface->dev, &dev_attr_led_green)); | ||
432 | } | ||
433 | |||
434 | toneport_setup(toneport); | ||
435 | |||
436 | init_timer(&toneport->timer); | ||
437 | toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ; | ||
438 | toneport->timer.function = toneport_start_pcm; | ||
439 | toneport->timer.data = (unsigned long)toneport; | ||
440 | add_timer(&toneport->timer); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | Init Toneport device (and clean up in case of failure). | ||
447 | */ | ||
448 | int line6_toneport_init(struct usb_interface *interface, | ||
449 | struct usb_line6 *line6) | ||
450 | { | ||
451 | int err = toneport_try_init(interface, line6); | ||
452 | |||
453 | if (err < 0) | ||
454 | toneport_destruct(interface); | ||
455 | |||
456 | return err; | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | Resume Toneport device after reset. | ||
461 | */ | ||
462 | void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) | ||
463 | { | ||
464 | toneport_setup(toneport); | ||
465 | } | ||
diff --git a/sound/usb/line6/toneport.h b/sound/usb/line6/toneport.h new file mode 100644 index 000000000000..8cb14426f6ae --- /dev/null +++ b/sound/usb/line6/toneport.h | |||
@@ -0,0 +1,51 @@ | |||
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 | #ifndef TONEPORT_H | ||
13 | #define TONEPORT_H | ||
14 | |||
15 | #include <linux/usb.h> | ||
16 | #include <sound/core.h> | ||
17 | |||
18 | #include "driver.h" | ||
19 | |||
20 | struct usb_line6_toneport { | ||
21 | /** | ||
22 | Generic Line6 USB data. | ||
23 | */ | ||
24 | struct usb_line6 line6; | ||
25 | |||
26 | /** | ||
27 | Source selector. | ||
28 | */ | ||
29 | int source; | ||
30 | |||
31 | /** | ||
32 | Serial number of device. | ||
33 | */ | ||
34 | int serial_number; | ||
35 | |||
36 | /** | ||
37 | Firmware version (x 100). | ||
38 | */ | ||
39 | int firmware_version; | ||
40 | |||
41 | /** | ||
42 | Timer for delayed PCM startup. | ||
43 | */ | ||
44 | struct timer_list timer; | ||
45 | }; | ||
46 | |||
47 | extern int line6_toneport_init(struct usb_interface *interface, | ||
48 | struct usb_line6 *line6); | ||
49 | extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport); | ||
50 | |||
51 | #endif | ||
diff --git a/sound/usb/line6/usbdefs.h b/sound/usb/line6/usbdefs.h new file mode 100644 index 000000000000..f4d080e69abc --- /dev/null +++ b/sound/usb/line6/usbdefs.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Line6 Linux USB driver - 0.9.1beta | ||
3 | * | ||
4 | * Copyright (C) 2005-2008 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 | #ifndef USBDEFS_H | ||
13 | #define USBDEFS_H | ||
14 | |||
15 | #define USB_INTERVALS_PER_SECOND 1000 | ||
16 | |||
17 | /* device supports settings parameter via USB */ | ||
18 | #define LINE6_CAP_CONTROL (1 << 0) | ||
19 | /* device supports PCM input/output via USB */ | ||
20 | #define LINE6_CAP_PCM (1 << 1) | ||
21 | /* device support hardware monitoring */ | ||
22 | #define LINE6_CAP_HWMON (1 << 2) | ||
23 | |||
24 | #define LINE6_FALLBACK_INTERVAL 10 | ||
25 | #define LINE6_FALLBACK_MAXPACKETSIZE 16 | ||
26 | |||
27 | #endif | ||
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c new file mode 100644 index 000000000000..b4a41b0ad0ea --- /dev/null +++ b/sound/usb/line6/variax.c | |||
@@ -0,0 +1,239 @@ | |||
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 | |||
14 | #include "audio.h" | ||
15 | #include "driver.h" | ||
16 | #include "variax.h" | ||
17 | |||
18 | #define VARIAX_OFFSET_ACTIVATE 7 | ||
19 | |||
20 | /* | ||
21 | This message is sent by the device during initialization and identifies | ||
22 | the connected guitar version. | ||
23 | */ | ||
24 | static const char variax_init_version[] = { | ||
25 | 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, | ||
26 | 0x07, 0x00, 0x00, 0x00 | ||
27 | }; | ||
28 | |||
29 | /* | ||
30 | This message is the last one sent by the device during initialization. | ||
31 | */ | ||
32 | static const char variax_init_done[] = { | ||
33 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b | ||
34 | }; | ||
35 | |||
36 | static const char variax_activate[] = { | ||
37 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, | ||
38 | 0xf7 | ||
39 | }; | ||
40 | |||
41 | /* forward declarations: */ | ||
42 | static void variax_startup2(unsigned long data); | ||
43 | static void variax_startup4(unsigned long data); | ||
44 | static void variax_startup5(unsigned long data); | ||
45 | |||
46 | static void variax_activate_async(struct usb_line6_variax *variax, int a) | ||
47 | { | ||
48 | variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; | ||
49 | line6_send_raw_message_async(&variax->line6, variax->buffer_activate, | ||
50 | sizeof(variax_activate)); | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | Variax startup procedure. | ||
55 | This is a sequence of functions with special requirements (e.g., must | ||
56 | not run immediately after initialization, must not run in interrupt | ||
57 | context). After the last one has finished, the device is ready to use. | ||
58 | */ | ||
59 | |||
60 | static void variax_startup1(struct usb_line6_variax *variax) | ||
61 | { | ||
62 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); | ||
63 | |||
64 | /* delay startup procedure: */ | ||
65 | line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, | ||
66 | variax_startup2, (unsigned long)variax); | ||
67 | } | ||
68 | |||
69 | static void variax_startup2(unsigned long data) | ||
70 | { | ||
71 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; | ||
72 | struct usb_line6 *line6 = &variax->line6; | ||
73 | |||
74 | /* schedule another startup procedure until startup is complete: */ | ||
75 | if (variax->startup_progress >= VARIAX_STARTUP_LAST) | ||
76 | return; | ||
77 | |||
78 | variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; | ||
79 | line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, | ||
80 | variax_startup2, (unsigned long)variax); | ||
81 | |||
82 | /* request firmware version: */ | ||
83 | line6_version_request_async(line6); | ||
84 | } | ||
85 | |||
86 | static void variax_startup3(struct usb_line6_variax *variax) | ||
87 | { | ||
88 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); | ||
89 | |||
90 | /* delay startup procedure: */ | ||
91 | line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, | ||
92 | variax_startup4, (unsigned long)variax); | ||
93 | } | ||
94 | |||
95 | static void variax_startup4(unsigned long data) | ||
96 | { | ||
97 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; | ||
98 | |||
99 | CHECK_STARTUP_PROGRESS(variax->startup_progress, | ||
100 | VARIAX_STARTUP_ACTIVATE); | ||
101 | |||
102 | /* activate device: */ | ||
103 | variax_activate_async(variax, 1); | ||
104 | line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, | ||
105 | variax_startup5, (unsigned long)variax); | ||
106 | } | ||
107 | |||
108 | static void variax_startup5(unsigned long data) | ||
109 | { | ||
110 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; | ||
111 | |||
112 | CHECK_STARTUP_PROGRESS(variax->startup_progress, | ||
113 | VARIAX_STARTUP_WORKQUEUE); | ||
114 | |||
115 | /* schedule work for global work queue: */ | ||
116 | schedule_work(&variax->startup_work); | ||
117 | } | ||
118 | |||
119 | static void variax_startup6(struct work_struct *work) | ||
120 | { | ||
121 | struct usb_line6_variax *variax = | ||
122 | container_of(work, struct usb_line6_variax, startup_work); | ||
123 | |||
124 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); | ||
125 | |||
126 | /* ALSA audio interface: */ | ||
127 | line6_register_audio(&variax->line6); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | Process a completely received message. | ||
132 | */ | ||
133 | static void line6_variax_process_message(struct usb_line6 *line6) | ||
134 | { | ||
135 | struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; | ||
136 | const unsigned char *buf = variax->line6.buffer_message; | ||
137 | |||
138 | switch (buf[0]) { | ||
139 | case LINE6_RESET: | ||
140 | dev_info(variax->line6.ifcdev, "VARIAX reset\n"); | ||
141 | break; | ||
142 | |||
143 | case LINE6_SYSEX_BEGIN: | ||
144 | if (memcmp(buf + 1, variax_init_version + 1, | ||
145 | sizeof(variax_init_version) - 1) == 0) { | ||
146 | variax_startup3(variax); | ||
147 | } else if (memcmp(buf + 1, variax_init_done + 1, | ||
148 | sizeof(variax_init_done) - 1) == 0) { | ||
149 | /* notify of complete initialization: */ | ||
150 | variax_startup4((unsigned long)variax); | ||
151 | } | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | /* | ||
157 | Variax destructor. | ||
158 | */ | ||
159 | static void variax_destruct(struct usb_interface *interface) | ||
160 | { | ||
161 | struct usb_line6_variax *variax = usb_get_intfdata(interface); | ||
162 | |||
163 | if (variax == NULL) | ||
164 | return; | ||
165 | line6_cleanup_audio(&variax->line6); | ||
166 | |||
167 | del_timer(&variax->startup_timer1); | ||
168 | del_timer(&variax->startup_timer2); | ||
169 | cancel_work_sync(&variax->startup_work); | ||
170 | |||
171 | kfree(variax->buffer_activate); | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | Workbench device disconnected. | ||
176 | */ | ||
177 | static void line6_variax_disconnect(struct usb_interface *interface) | ||
178 | { | ||
179 | if (interface == NULL) | ||
180 | return; | ||
181 | |||
182 | variax_destruct(interface); | ||
183 | } | ||
184 | |||
185 | /* | ||
186 | Try to init workbench device. | ||
187 | */ | ||
188 | static int variax_try_init(struct usb_interface *interface, | ||
189 | struct usb_line6 *line6) | ||
190 | { | ||
191 | struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; | ||
192 | int err; | ||
193 | |||
194 | line6->process_message = line6_variax_process_message; | ||
195 | line6->disconnect = line6_variax_disconnect; | ||
196 | |||
197 | init_timer(&variax->startup_timer1); | ||
198 | init_timer(&variax->startup_timer2); | ||
199 | INIT_WORK(&variax->startup_work, variax_startup6); | ||
200 | |||
201 | if ((interface == NULL) || (variax == NULL)) | ||
202 | return -ENODEV; | ||
203 | |||
204 | /* initialize USB buffers: */ | ||
205 | variax->buffer_activate = kmemdup(variax_activate, | ||
206 | sizeof(variax_activate), GFP_KERNEL); | ||
207 | |||
208 | if (variax->buffer_activate == NULL) { | ||
209 | dev_err(&interface->dev, "Out of memory\n"); | ||
210 | return -ENOMEM; | ||
211 | } | ||
212 | |||
213 | /* initialize audio system: */ | ||
214 | err = line6_init_audio(&variax->line6); | ||
215 | if (err < 0) | ||
216 | return err; | ||
217 | |||
218 | /* initialize MIDI subsystem: */ | ||
219 | err = line6_init_midi(&variax->line6); | ||
220 | if (err < 0) | ||
221 | return err; | ||
222 | |||
223 | /* initiate startup procedure: */ | ||
224 | variax_startup1(variax); | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | Init workbench device (and clean up in case of failure). | ||
230 | */ | ||
231 | int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) | ||
232 | { | ||
233 | int err = variax_try_init(interface, line6); | ||
234 | |||
235 | if (err < 0) | ||
236 | variax_destruct(interface); | ||
237 | |||
238 | return err; | ||
239 | } | ||
diff --git a/sound/usb/line6/variax.h b/sound/usb/line6/variax.h new file mode 100644 index 000000000000..dfb94e574cc4 --- /dev/null +++ b/sound/usb/line6/variax.h | |||
@@ -0,0 +1,70 @@ | |||
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 | #ifndef VARIAX_H | ||
13 | #define VARIAX_H | ||
14 | |||
15 | #include <linux/spinlock.h> | ||
16 | #include <linux/usb.h> | ||
17 | #include <linux/wait.h> | ||
18 | #include <sound/core.h> | ||
19 | |||
20 | #include "driver.h" | ||
21 | |||
22 | #define VARIAX_STARTUP_DELAY1 1000 | ||
23 | #define VARIAX_STARTUP_DELAY3 100 | ||
24 | #define VARIAX_STARTUP_DELAY4 100 | ||
25 | |||
26 | /* | ||
27 | Stages of Variax startup procedure | ||
28 | */ | ||
29 | enum { | ||
30 | VARIAX_STARTUP_INIT = 1, | ||
31 | VARIAX_STARTUP_VERSIONREQ, | ||
32 | VARIAX_STARTUP_WAIT, | ||
33 | VARIAX_STARTUP_ACTIVATE, | ||
34 | VARIAX_STARTUP_WORKQUEUE, | ||
35 | VARIAX_STARTUP_SETUP, | ||
36 | VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 | ||
37 | }; | ||
38 | |||
39 | struct usb_line6_variax { | ||
40 | /** | ||
41 | Generic Line6 USB data. | ||
42 | */ | ||
43 | struct usb_line6 line6; | ||
44 | |||
45 | /** | ||
46 | Buffer for activation code. | ||
47 | */ | ||
48 | unsigned char *buffer_activate; | ||
49 | |||
50 | /** | ||
51 | Handler for device initializaton. | ||
52 | */ | ||
53 | struct work_struct startup_work; | ||
54 | |||
55 | /** | ||
56 | Timers for device initializaton. | ||
57 | */ | ||
58 | struct timer_list startup_timer1; | ||
59 | struct timer_list startup_timer2; | ||
60 | |||
61 | /** | ||
62 | Current progress in startup procedure. | ||
63 | */ | ||
64 | int startup_progress; | ||
65 | }; | ||
66 | |||
67 | extern int line6_variax_init(struct usb_interface *interface, | ||
68 | struct usb_line6 *line6); | ||
69 | |||
70 | #endif | ||