diff options
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/Kconfig | 2 | ||||
-rw-r--r-- | sound/usb/Makefile | 1 | ||||
-rw-r--r-- | sound/usb/card.h | 2 | ||||
-rw-r--r-- | sound/usb/line6/Kconfig | 42 | ||||
-rw-r--r-- | sound/usb/line6/Makefile | 18 | ||||
-rw-r--r-- | sound/usb/line6/capture.c | 275 | ||||
-rw-r--r-- | sound/usb/line6/capture.h | 29 | ||||
-rw-r--r-- | sound/usb/line6/driver.c | 666 | ||||
-rw-r--r-- | sound/usb/line6/driver.h | 181 | ||||
-rw-r--r-- | sound/usb/line6/midi.c | 292 | ||||
-rw-r--r-- | sound/usb/line6/midi.h | 51 | ||||
-rw-r--r-- | sound/usb/line6/midibuf.c | 252 | ||||
-rw-r--r-- | sound/usb/line6/midibuf.h | 35 | ||||
-rw-r--r-- | sound/usb/line6/pcm.c | 588 | ||||
-rw-r--r-- | sound/usb/line6/pcm.h | 197 | ||||
-rw-r--r-- | sound/usb/line6/playback.c | 429 | ||||
-rw-r--r-- | sound/usb/line6/playback.h | 35 | ||||
-rw-r--r-- | sound/usb/line6/pod.c | 584 | ||||
-rw-r--r-- | sound/usb/line6/podhd.c | 192 | ||||
-rw-r--r-- | sound/usb/line6/toneport.c | 580 | ||||
-rw-r--r-- | sound/usb/line6/variax.c | 306 | ||||
-rw-r--r-- | sound/usb/midi.c | 5 | ||||
-rw-r--r-- | sound/usb/pcm.c | 9 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 22 | ||||
-rw-r--r-- | sound/usb/usx2y/usb_stream.h | 78 |
25 files changed, 4794 insertions, 77 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..2d2d122b069f 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_SND_USB_LINE6) += line6/ | ||
diff --git a/sound/usb/card.h b/sound/usb/card.h index 97acb906acc2..ef580b43f1e3 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
@@ -153,6 +153,8 @@ struct snd_usb_substream { | |||
153 | int channel; | 153 | int channel; |
154 | int byte_idx; | 154 | int byte_idx; |
155 | } dsd_dop; | 155 | } dsd_dop; |
156 | |||
157 | bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ | ||
156 | }; | 158 | }; |
157 | 159 | ||
158 | struct snd_usb_stream { | 160 | struct snd_usb_stream { |
diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig new file mode 100644 index 000000000000..f4585d378ef3 --- /dev/null +++ b/sound/usb/line6/Kconfig | |||
@@ -0,0 +1,42 @@ | |||
1 | config SND_USB_LINE6 | ||
2 | tristate | ||
3 | select SND_RAWMIDI | ||
4 | select SND_PCM | ||
5 | |||
6 | config SND_USB_POD | ||
7 | tristate "Line 6 POD USB support" | ||
8 | select SND_USB_LINE6 | ||
9 | help | ||
10 | This is a driver for PODxt and other similar devices, | ||
11 | supporting the following features: | ||
12 | * Reading/writing individual parameters | ||
13 | * Reading/writing complete channel, effects setup, and amp | ||
14 | setup data | ||
15 | * Channel switching | ||
16 | * Virtual MIDI interface | ||
17 | * Tuner access | ||
18 | * Playback/capture/mixer device for any ALSA-compatible PCM | ||
19 | audio application | ||
20 | * Signal routing (record clean/processed guitar signal, | ||
21 | re-amping) | ||
22 | |||
23 | config SND_USB_PODHD | ||
24 | tristate "Line 6 POD HD300/400/500 USB support" | ||
25 | select SND_USB_LINE6 | ||
26 | help | ||
27 | This is a driver for POD HD300, 400 and 500 devices. | ||
28 | |||
29 | config SND_USB_TONEPORT | ||
30 | tristate "TonePort GX, UX1 and UX2 USB support" | ||
31 | select SND_USB_LINE6 | ||
32 | select NEW_LEDS | ||
33 | select LEDS_CLASS | ||
34 | help | ||
35 | This is a driver for TonePort GX, UX1 and UX2 devices. | ||
36 | |||
37 | config SND_USB_VARIAX | ||
38 | tristate "Variax Workbench USB support" | ||
39 | select SND_USB_LINE6 | ||
40 | help | ||
41 | This is a driver for Variax Workbench device. | ||
42 | |||
diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile new file mode 100644 index 000000000000..b8b3b2a543d8 --- /dev/null +++ b/sound/usb/line6/Makefile | |||
@@ -0,0 +1,18 @@ | |||
1 | snd-usb-line6-y := \ | ||
2 | capture.o \ | ||
3 | driver.o \ | ||
4 | midi.o \ | ||
5 | midibuf.o \ | ||
6 | pcm.o \ | ||
7 | playback.o | ||
8 | |||
9 | snd-usb-pod-y := pod.o | ||
10 | snd-usb-podhd-y := podhd.o | ||
11 | snd-usb-toneport-y := toneport.o | ||
12 | snd-usb-variax-y := variax.o | ||
13 | |||
14 | obj-$(CONFIG_SND_USB_LINE6) += snd-usb-line6.o | ||
15 | obj-$(CONFIG_SND_USB_POD) += snd-usb-pod.o | ||
16 | obj-$(CONFIG_SND_USB_PODHD) += snd-usb-podhd.o | ||
17 | obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o | ||
18 | obj-$(CONFIG_SND_USB_VARIAX) += snd-usb-variax.o | ||
diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c new file mode 100644 index 000000000000..f518fbbe88de --- /dev/null +++ b/sound/usb/line6/capture.c | |||
@@ -0,0 +1,275 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 "capture.h" | ||
18 | #include "driver.h" | ||
19 | #include "pcm.h" | ||
20 | |||
21 | /* | ||
22 | Find a free URB and submit it. | ||
23 | must be called in line6pcm->in.lock context | ||
24 | */ | ||
25 | static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) | ||
26 | { | ||
27 | int index; | ||
28 | int i, urb_size; | ||
29 | int ret; | ||
30 | struct urb *urb_in; | ||
31 | |||
32 | index = | ||
33 | find_first_zero_bit(&line6pcm->in.active_urbs, LINE6_ISO_BUFFERS); | ||
34 | |||
35 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { | ||
36 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); | ||
37 | return -EINVAL; | ||
38 | } | ||
39 | |||
40 | urb_in = line6pcm->in.urbs[index]; | ||
41 | urb_size = 0; | ||
42 | |||
43 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | ||
44 | struct usb_iso_packet_descriptor *fin = | ||
45 | &urb_in->iso_frame_desc[i]; | ||
46 | fin->offset = urb_size; | ||
47 | fin->length = line6pcm->max_packet_size; | ||
48 | urb_size += line6pcm->max_packet_size; | ||
49 | } | ||
50 | |||
51 | urb_in->transfer_buffer = | ||
52 | line6pcm->in.buffer + | ||
53 | index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; | ||
54 | urb_in->transfer_buffer_length = urb_size; | ||
55 | urb_in->context = line6pcm; | ||
56 | |||
57 | ret = usb_submit_urb(urb_in, GFP_ATOMIC); | ||
58 | |||
59 | if (ret == 0) | ||
60 | set_bit(index, &line6pcm->in.active_urbs); | ||
61 | else | ||
62 | dev_err(line6pcm->line6->ifcdev, | ||
63 | "URB in #%d submission failed (%d)\n", index, ret); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | Submit all currently available capture URBs. | ||
70 | must be called in line6pcm->in.lock context | ||
71 | */ | ||
72 | int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) | ||
73 | { | ||
74 | int ret = 0, i; | ||
75 | |||
76 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
77 | ret = submit_audio_in_urb(line6pcm); | ||
78 | if (ret < 0) | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | Copy data into ALSA capture buffer. | ||
87 | */ | ||
88 | void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) | ||
89 | { | ||
90 | struct snd_pcm_substream *substream = | ||
91 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
92 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
93 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; | ||
94 | int frames = fsize / bytes_per_frame; | ||
95 | |||
96 | if (runtime == NULL) | ||
97 | return; | ||
98 | |||
99 | if (line6pcm->in.pos_done + frames > runtime->buffer_size) { | ||
100 | /* | ||
101 | The transferred area goes over buffer boundary, | ||
102 | copy two separate chunks. | ||
103 | */ | ||
104 | int len; | ||
105 | |||
106 | len = runtime->buffer_size - line6pcm->in.pos_done; | ||
107 | |||
108 | if (len > 0) { | ||
109 | memcpy(runtime->dma_area + | ||
110 | line6pcm->in.pos_done * bytes_per_frame, fbuf, | ||
111 | len * bytes_per_frame); | ||
112 | memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, | ||
113 | (frames - len) * bytes_per_frame); | ||
114 | } else { | ||
115 | /* this is somewhat paranoid */ | ||
116 | dev_err(line6pcm->line6->ifcdev, | ||
117 | "driver bug: len = %d\n", len); | ||
118 | } | ||
119 | } else { | ||
120 | /* copy single chunk */ | ||
121 | memcpy(runtime->dma_area + | ||
122 | line6pcm->in.pos_done * bytes_per_frame, fbuf, fsize); | ||
123 | } | ||
124 | |||
125 | line6pcm->in.pos_done += frames; | ||
126 | if (line6pcm->in.pos_done >= runtime->buffer_size) | ||
127 | line6pcm->in.pos_done -= runtime->buffer_size; | ||
128 | } | ||
129 | |||
130 | void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) | ||
131 | { | ||
132 | struct snd_pcm_substream *substream = | ||
133 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
134 | |||
135 | line6pcm->in.bytes += length; | ||
136 | if (line6pcm->in.bytes >= line6pcm->in.period) { | ||
137 | line6pcm->in.bytes %= line6pcm->in.period; | ||
138 | spin_unlock(&line6pcm->in.lock); | ||
139 | snd_pcm_period_elapsed(substream); | ||
140 | spin_lock(&line6pcm->in.lock); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Callback for completed capture URB. | ||
146 | */ | ||
147 | static void audio_in_callback(struct urb *urb) | ||
148 | { | ||
149 | int i, index, length = 0, shutdown = 0; | ||
150 | unsigned long flags; | ||
151 | |||
152 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; | ||
153 | |||
154 | line6pcm->in.last_frame = urb->start_frame; | ||
155 | |||
156 | /* find index of URB */ | ||
157 | for (index = 0; index < LINE6_ISO_BUFFERS; ++index) | ||
158 | if (urb == line6pcm->in.urbs[index]) | ||
159 | break; | ||
160 | |||
161 | spin_lock_irqsave(&line6pcm->in.lock, flags); | ||
162 | |||
163 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | ||
164 | char *fbuf; | ||
165 | int fsize; | ||
166 | struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; | ||
167 | |||
168 | if (fin->status == -EXDEV) { | ||
169 | shutdown = 1; | ||
170 | break; | ||
171 | } | ||
172 | |||
173 | fbuf = urb->transfer_buffer + fin->offset; | ||
174 | fsize = fin->actual_length; | ||
175 | |||
176 | if (fsize > line6pcm->max_packet_size) { | ||
177 | dev_err(line6pcm->line6->ifcdev, | ||
178 | "driver and/or device bug: packet too large (%d > %d)\n", | ||
179 | fsize, line6pcm->max_packet_size); | ||
180 | } | ||
181 | |||
182 | length += fsize; | ||
183 | |||
184 | /* the following assumes LINE6_ISO_PACKETS == 1: */ | ||
185 | line6pcm->prev_fbuf = fbuf; | ||
186 | line6pcm->prev_fsize = fsize; | ||
187 | |||
188 | if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && | ||
189 | test_bit(LINE6_STREAM_PCM, &line6pcm->in.running) && | ||
190 | fsize > 0) | ||
191 | line6_capture_copy(line6pcm, fbuf, fsize); | ||
192 | } | ||
193 | |||
194 | clear_bit(index, &line6pcm->in.active_urbs); | ||
195 | |||
196 | if (test_and_clear_bit(index, &line6pcm->in.unlink_urbs)) | ||
197 | shutdown = 1; | ||
198 | |||
199 | if (!shutdown) { | ||
200 | submit_audio_in_urb(line6pcm); | ||
201 | |||
202 | if (!test_bit(LINE6_STREAM_IMPULSE, &line6pcm->in.running) && | ||
203 | test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) | ||
204 | line6_capture_check_period(line6pcm, length); | ||
205 | } | ||
206 | |||
207 | spin_unlock_irqrestore(&line6pcm->in.lock, flags); | ||
208 | } | ||
209 | |||
210 | /* open capture callback */ | ||
211 | static int snd_line6_capture_open(struct snd_pcm_substream *substream) | ||
212 | { | ||
213 | int err; | ||
214 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
215 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
216 | |||
217 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, | ||
218 | SNDRV_PCM_HW_PARAM_RATE, | ||
219 | &line6pcm->properties->rates); | ||
220 | if (err < 0) | ||
221 | return err; | ||
222 | |||
223 | runtime->hw = line6pcm->properties->capture_hw; | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* close capture callback */ | ||
228 | static int snd_line6_capture_close(struct snd_pcm_substream *substream) | ||
229 | { | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | /* capture operators */ | ||
234 | struct snd_pcm_ops snd_line6_capture_ops = { | ||
235 | .open = snd_line6_capture_open, | ||
236 | .close = snd_line6_capture_close, | ||
237 | .ioctl = snd_pcm_lib_ioctl, | ||
238 | .hw_params = snd_line6_hw_params, | ||
239 | .hw_free = snd_line6_hw_free, | ||
240 | .prepare = snd_line6_prepare, | ||
241 | .trigger = snd_line6_trigger, | ||
242 | .pointer = snd_line6_pointer, | ||
243 | }; | ||
244 | |||
245 | int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) | ||
246 | { | ||
247 | struct usb_line6 *line6 = line6pcm->line6; | ||
248 | int i; | ||
249 | |||
250 | /* create audio URBs and fill in constant values: */ | ||
251 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
252 | struct urb *urb; | ||
253 | |||
254 | /* URB for audio in: */ | ||
255 | urb = line6pcm->in.urbs[i] = | ||
256 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); | ||
257 | |||
258 | if (urb == NULL) | ||
259 | return -ENOMEM; | ||
260 | |||
261 | urb->dev = line6->usbdev; | ||
262 | urb->pipe = | ||
263 | usb_rcvisocpipe(line6->usbdev, | ||
264 | line6->properties->ep_audio_r & | ||
265 | USB_ENDPOINT_NUMBER_MASK); | ||
266 | urb->transfer_flags = URB_ISO_ASAP; | ||
267 | urb->start_frame = -1; | ||
268 | urb->number_of_packets = LINE6_ISO_PACKETS; | ||
269 | urb->interval = LINE6_ISO_INTERVAL; | ||
270 | urb->error_count = 0; | ||
271 | urb->complete = audio_in_callback; | ||
272 | } | ||
273 | |||
274 | return 0; | ||
275 | } | ||
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h new file mode 100644 index 000000000000..890b21bff18c --- /dev/null +++ b/sound/usb/line6/capture.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm); | ||
28 | |||
29 | #endif | ||
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c new file mode 100644 index 000000000000..99b63a7902f3 --- /dev/null +++ b/sound/usb/line6/driver.c | |||
@@ -0,0 +1,666 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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/export.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/usb.h> | ||
17 | |||
18 | #include <sound/core.h> | ||
19 | #include <sound/initval.h> | ||
20 | |||
21 | #include "capture.h" | ||
22 | #include "driver.h" | ||
23 | #include "midi.h" | ||
24 | #include "playback.h" | ||
25 | |||
26 | #define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>" | ||
27 | #define DRIVER_DESC "Line 6 USB Driver" | ||
28 | |||
29 | /* | ||
30 | This is Line 6's MIDI manufacturer ID. | ||
31 | */ | ||
32 | const unsigned char line6_midi_id[] = { | ||
33 | 0x00, 0x01, 0x0c | ||
34 | }; | ||
35 | EXPORT_SYMBOL_GPL(line6_midi_id); | ||
36 | |||
37 | /* | ||
38 | Code to request version of POD, Variax interface | ||
39 | (and maybe other devices). | ||
40 | */ | ||
41 | static const char line6_request_version[] = { | ||
42 | 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 | ||
43 | }; | ||
44 | |||
45 | /* | ||
46 | Class for asynchronous messages. | ||
47 | */ | ||
48 | struct message { | ||
49 | struct usb_line6 *line6; | ||
50 | const char *buffer; | ||
51 | int size; | ||
52 | int done; | ||
53 | }; | ||
54 | |||
55 | /* | ||
56 | Forward declarations. | ||
57 | */ | ||
58 | static void line6_data_received(struct urb *urb); | ||
59 | static int line6_send_raw_message_async_part(struct message *msg, | ||
60 | struct urb *urb); | ||
61 | |||
62 | /* | ||
63 | Start to listen on endpoint. | ||
64 | */ | ||
65 | static int line6_start_listen(struct usb_line6 *line6) | ||
66 | { | ||
67 | int err; | ||
68 | |||
69 | usb_fill_int_urb(line6->urb_listen, line6->usbdev, | ||
70 | usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r), | ||
71 | line6->buffer_listen, LINE6_BUFSIZE_LISTEN, | ||
72 | line6_data_received, line6, line6->interval); | ||
73 | line6->urb_listen->actual_length = 0; | ||
74 | err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); | ||
75 | return err; | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | Stop listening on endpoint. | ||
80 | */ | ||
81 | static void line6_stop_listen(struct usb_line6 *line6) | ||
82 | { | ||
83 | usb_kill_urb(line6->urb_listen); | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | Send raw message in pieces of wMaxPacketSize bytes. | ||
88 | */ | ||
89 | static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, | ||
90 | int size) | ||
91 | { | ||
92 | int i, done = 0; | ||
93 | |||
94 | for (i = 0; i < size; i += line6->max_packet_size) { | ||
95 | int partial; | ||
96 | const char *frag_buf = buffer + i; | ||
97 | int frag_size = min(line6->max_packet_size, size - i); | ||
98 | int retval; | ||
99 | |||
100 | retval = usb_interrupt_msg(line6->usbdev, | ||
101 | usb_sndintpipe(line6->usbdev, | ||
102 | line6->properties->ep_ctrl_w), | ||
103 | (char *)frag_buf, frag_size, | ||
104 | &partial, LINE6_TIMEOUT * HZ); | ||
105 | |||
106 | if (retval) { | ||
107 | dev_err(line6->ifcdev, | ||
108 | "usb_interrupt_msg failed (%d)\n", retval); | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | done += frag_size; | ||
113 | } | ||
114 | |||
115 | return done; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | Notification of completion of asynchronous request transmission. | ||
120 | */ | ||
121 | static void line6_async_request_sent(struct urb *urb) | ||
122 | { | ||
123 | struct message *msg = (struct message *)urb->context; | ||
124 | |||
125 | if (msg->done >= msg->size) { | ||
126 | usb_free_urb(urb); | ||
127 | kfree(msg); | ||
128 | } else | ||
129 | line6_send_raw_message_async_part(msg, urb); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | Asynchronously send part of a raw message. | ||
134 | */ | ||
135 | static int line6_send_raw_message_async_part(struct message *msg, | ||
136 | struct urb *urb) | ||
137 | { | ||
138 | int retval; | ||
139 | struct usb_line6 *line6 = msg->line6; | ||
140 | int done = msg->done; | ||
141 | int bytes = min(msg->size - done, line6->max_packet_size); | ||
142 | |||
143 | usb_fill_int_urb(urb, line6->usbdev, | ||
144 | usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w), | ||
145 | (char *)msg->buffer + done, bytes, | ||
146 | line6_async_request_sent, msg, line6->interval); | ||
147 | |||
148 | msg->done += bytes; | ||
149 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
150 | |||
151 | if (retval < 0) { | ||
152 | dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", | ||
153 | __func__, retval); | ||
154 | usb_free_urb(urb); | ||
155 | kfree(msg); | ||
156 | return retval; | ||
157 | } | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | Setup and start timer. | ||
164 | */ | ||
165 | void line6_start_timer(struct timer_list *timer, unsigned long msecs, | ||
166 | void (*function)(unsigned long), unsigned long data) | ||
167 | { | ||
168 | setup_timer(timer, function, data); | ||
169 | mod_timer(timer, jiffies + msecs_to_jiffies(msecs)); | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(line6_start_timer); | ||
172 | |||
173 | /* | ||
174 | Asynchronously send raw message. | ||
175 | */ | ||
176 | int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, | ||
177 | int size) | ||
178 | { | ||
179 | struct message *msg; | ||
180 | struct urb *urb; | ||
181 | |||
182 | /* create message: */ | ||
183 | msg = kmalloc(sizeof(struct message), GFP_ATOMIC); | ||
184 | if (msg == NULL) | ||
185 | return -ENOMEM; | ||
186 | |||
187 | /* create URB: */ | ||
188 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
189 | |||
190 | if (urb == NULL) { | ||
191 | kfree(msg); | ||
192 | return -ENOMEM; | ||
193 | } | ||
194 | |||
195 | /* set message data: */ | ||
196 | msg->line6 = line6; | ||
197 | msg->buffer = buffer; | ||
198 | msg->size = size; | ||
199 | msg->done = 0; | ||
200 | |||
201 | /* start sending: */ | ||
202 | return line6_send_raw_message_async_part(msg, urb); | ||
203 | } | ||
204 | EXPORT_SYMBOL_GPL(line6_send_raw_message_async); | ||
205 | |||
206 | /* | ||
207 | Send asynchronous device version request. | ||
208 | */ | ||
209 | int line6_version_request_async(struct usb_line6 *line6) | ||
210 | { | ||
211 | char *buffer; | ||
212 | int retval; | ||
213 | |||
214 | buffer = kmemdup(line6_request_version, | ||
215 | sizeof(line6_request_version), GFP_ATOMIC); | ||
216 | if (buffer == NULL) | ||
217 | return -ENOMEM; | ||
218 | |||
219 | retval = line6_send_raw_message_async(line6, buffer, | ||
220 | sizeof(line6_request_version)); | ||
221 | kfree(buffer); | ||
222 | return retval; | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(line6_version_request_async); | ||
225 | |||
226 | /* | ||
227 | Send sysex message in pieces of wMaxPacketSize bytes. | ||
228 | */ | ||
229 | int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, | ||
230 | int size) | ||
231 | { | ||
232 | return line6_send_raw_message(line6, buffer, | ||
233 | size + SYSEX_EXTRA_SIZE) - | ||
234 | SYSEX_EXTRA_SIZE; | ||
235 | } | ||
236 | EXPORT_SYMBOL_GPL(line6_send_sysex_message); | ||
237 | |||
238 | /* | ||
239 | Allocate buffer for sysex message and prepare header. | ||
240 | @param code sysex message code | ||
241 | @param size number of bytes between code and sysex end | ||
242 | */ | ||
243 | char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, | ||
244 | int size) | ||
245 | { | ||
246 | char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); | ||
247 | |||
248 | if (!buffer) | ||
249 | return NULL; | ||
250 | |||
251 | buffer[0] = LINE6_SYSEX_BEGIN; | ||
252 | memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); | ||
253 | buffer[sizeof(line6_midi_id) + 1] = code1; | ||
254 | buffer[sizeof(line6_midi_id) + 2] = code2; | ||
255 | buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; | ||
256 | return buffer; | ||
257 | } | ||
258 | EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer); | ||
259 | |||
260 | /* | ||
261 | Notification of data received from the Line 6 device. | ||
262 | */ | ||
263 | static void line6_data_received(struct urb *urb) | ||
264 | { | ||
265 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; | ||
266 | struct midi_buffer *mb = &line6->line6midi->midibuf_in; | ||
267 | int done; | ||
268 | |||
269 | if (urb->status == -ESHUTDOWN) | ||
270 | return; | ||
271 | |||
272 | done = | ||
273 | line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); | ||
274 | |||
275 | if (done < urb->actual_length) { | ||
276 | line6_midibuf_ignore(mb, done); | ||
277 | dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", | ||
278 | done, urb->actual_length); | ||
279 | } | ||
280 | |||
281 | for (;;) { | ||
282 | done = | ||
283 | line6_midibuf_read(mb, line6->buffer_message, | ||
284 | LINE6_MESSAGE_MAXLEN); | ||
285 | |||
286 | if (done == 0) | ||
287 | break; | ||
288 | |||
289 | line6->message_length = done; | ||
290 | line6_midi_receive(line6, line6->buffer_message, done); | ||
291 | |||
292 | if (line6->process_message) | ||
293 | line6->process_message(line6); | ||
294 | } | ||
295 | |||
296 | line6_start_listen(line6); | ||
297 | } | ||
298 | |||
299 | #define LINE6_READ_WRITE_STATUS_DELAY 2 /* milliseconds */ | ||
300 | #define LINE6_READ_WRITE_MAX_RETRIES 50 | ||
301 | |||
302 | /* | ||
303 | Read data from device. | ||
304 | */ | ||
305 | int line6_read_data(struct usb_line6 *line6, int address, void *data, | ||
306 | size_t datalen) | ||
307 | { | ||
308 | struct usb_device *usbdev = line6->usbdev; | ||
309 | int ret; | ||
310 | unsigned char len; | ||
311 | unsigned count; | ||
312 | |||
313 | /* query the serial number: */ | ||
314 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | ||
315 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
316 | (datalen << 8) | 0x21, address, | ||
317 | NULL, 0, LINE6_TIMEOUT * HZ); | ||
318 | |||
319 | if (ret < 0) { | ||
320 | dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); | ||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | /* Wait for data length. We'll get 0xff until length arrives. */ | ||
325 | for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { | ||
326 | mdelay(LINE6_READ_WRITE_STATUS_DELAY); | ||
327 | |||
328 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | ||
329 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | ||
330 | USB_DIR_IN, | ||
331 | 0x0012, 0x0000, &len, 1, | ||
332 | LINE6_TIMEOUT * HZ); | ||
333 | if (ret < 0) { | ||
334 | dev_err(line6->ifcdev, | ||
335 | "receive length failed (error %d)\n", ret); | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | if (len != 0xff) | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | if (len == 0xff) { | ||
344 | dev_err(line6->ifcdev, "read failed after %d retries\n", | ||
345 | count); | ||
346 | return -EIO; | ||
347 | } else if (len != datalen) { | ||
348 | /* should be equal or something went wrong */ | ||
349 | dev_err(line6->ifcdev, | ||
350 | "length mismatch (expected %d, got %d)\n", | ||
351 | (int)datalen, (int)len); | ||
352 | return -EIO; | ||
353 | } | ||
354 | |||
355 | /* receive the result: */ | ||
356 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | ||
357 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | ||
358 | 0x0013, 0x0000, data, datalen, | ||
359 | LINE6_TIMEOUT * HZ); | ||
360 | |||
361 | if (ret < 0) { | ||
362 | dev_err(line6->ifcdev, "read failed (error %d)\n", ret); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | EXPORT_SYMBOL_GPL(line6_read_data); | ||
369 | |||
370 | /* | ||
371 | Write data to device. | ||
372 | */ | ||
373 | int line6_write_data(struct usb_line6 *line6, int address, void *data, | ||
374 | size_t datalen) | ||
375 | { | ||
376 | struct usb_device *usbdev = line6->usbdev; | ||
377 | int ret; | ||
378 | unsigned char status; | ||
379 | int count; | ||
380 | |||
381 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | ||
382 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
383 | 0x0022, address, data, datalen, | ||
384 | LINE6_TIMEOUT * HZ); | ||
385 | |||
386 | if (ret < 0) { | ||
387 | dev_err(line6->ifcdev, | ||
388 | "write request failed (error %d)\n", ret); | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { | ||
393 | mdelay(LINE6_READ_WRITE_STATUS_DELAY); | ||
394 | |||
395 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), | ||
396 | 0x67, | ||
397 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | ||
398 | USB_DIR_IN, | ||
399 | 0x0012, 0x0000, | ||
400 | &status, 1, LINE6_TIMEOUT * HZ); | ||
401 | |||
402 | if (ret < 0) { | ||
403 | dev_err(line6->ifcdev, | ||
404 | "receiving status failed (error %d)\n", ret); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | if (status != 0xff) | ||
409 | break; | ||
410 | } | ||
411 | |||
412 | if (status == 0xff) { | ||
413 | dev_err(line6->ifcdev, "write failed after %d retries\n", | ||
414 | count); | ||
415 | return -EIO; | ||
416 | } else if (status != 0) { | ||
417 | dev_err(line6->ifcdev, "write failed (error %d)\n", ret); | ||
418 | return -EIO; | ||
419 | } | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | EXPORT_SYMBOL_GPL(line6_write_data); | ||
424 | |||
425 | /* | ||
426 | Read Line 6 device serial number. | ||
427 | (POD, TonePort, GuitarPort) | ||
428 | */ | ||
429 | int line6_read_serial_number(struct usb_line6 *line6, u32 *serial_number) | ||
430 | { | ||
431 | return line6_read_data(line6, 0x80d0, serial_number, | ||
432 | sizeof(*serial_number)); | ||
433 | } | ||
434 | EXPORT_SYMBOL_GPL(line6_read_serial_number); | ||
435 | |||
436 | /* | ||
437 | Card destructor. | ||
438 | */ | ||
439 | static void line6_destruct(struct snd_card *card) | ||
440 | { | ||
441 | struct usb_line6 *line6 = card->private_data; | ||
442 | struct usb_device *usbdev = line6->usbdev; | ||
443 | |||
444 | /* free buffer memory first: */ | ||
445 | kfree(line6->buffer_message); | ||
446 | kfree(line6->buffer_listen); | ||
447 | |||
448 | /* then free URBs: */ | ||
449 | usb_free_urb(line6->urb_listen); | ||
450 | |||
451 | /* decrement reference counters: */ | ||
452 | usb_put_dev(usbdev); | ||
453 | } | ||
454 | |||
455 | /* get data from endpoint descriptor (see usb_maxpacket): */ | ||
456 | static void line6_get_interval(struct usb_line6 *line6) | ||
457 | { | ||
458 | struct usb_device *usbdev = line6->usbdev; | ||
459 | struct usb_host_endpoint *ep; | ||
460 | unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r); | ||
461 | unsigned epnum = usb_pipeendpoint(pipe); | ||
462 | |||
463 | ep = usbdev->ep_in[epnum]; | ||
464 | if (ep) { | ||
465 | line6->interval = ep->desc.bInterval; | ||
466 | line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); | ||
467 | } else { | ||
468 | dev_err(line6->ifcdev, | ||
469 | "endpoint not available, using fallback values"); | ||
470 | line6->interval = LINE6_FALLBACK_INTERVAL; | ||
471 | line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; | ||
472 | } | ||
473 | } | ||
474 | |||
475 | static int line6_init_cap_control(struct usb_line6 *line6) | ||
476 | { | ||
477 | int ret; | ||
478 | |||
479 | /* initialize USB buffers: */ | ||
480 | line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); | ||
481 | if (!line6->buffer_listen) | ||
482 | return -ENOMEM; | ||
483 | |||
484 | line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); | ||
485 | if (!line6->buffer_message) | ||
486 | return -ENOMEM; | ||
487 | |||
488 | line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); | ||
489 | if (!line6->urb_listen) | ||
490 | return -ENOMEM; | ||
491 | |||
492 | ret = line6_start_listen(line6); | ||
493 | if (ret < 0) { | ||
494 | dev_err(line6->ifcdev, "cannot start listening: %d\n", ret); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | Probe USB device. | ||
503 | */ | ||
504 | int line6_probe(struct usb_interface *interface, | ||
505 | const struct usb_device_id *id, | ||
506 | const char *driver_name, | ||
507 | const struct line6_properties *properties, | ||
508 | int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), | ||
509 | size_t data_size) | ||
510 | { | ||
511 | struct usb_device *usbdev = interface_to_usbdev(interface); | ||
512 | struct snd_card *card; | ||
513 | struct usb_line6 *line6; | ||
514 | int interface_number; | ||
515 | int ret; | ||
516 | |||
517 | if (WARN_ON(data_size < sizeof(*line6))) | ||
518 | return -EINVAL; | ||
519 | |||
520 | /* we don't handle multiple configurations */ | ||
521 | if (usbdev->descriptor.bNumConfigurations != 1) | ||
522 | return -ENODEV; | ||
523 | |||
524 | ret = snd_card_new(&interface->dev, | ||
525 | SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, | ||
526 | THIS_MODULE, data_size, &card); | ||
527 | if (ret < 0) | ||
528 | return ret; | ||
529 | |||
530 | /* store basic data: */ | ||
531 | line6 = card->private_data; | ||
532 | line6->card = card; | ||
533 | line6->properties = properties; | ||
534 | line6->usbdev = usbdev; | ||
535 | line6->ifcdev = &interface->dev; | ||
536 | |||
537 | strcpy(card->id, properties->id); | ||
538 | strcpy(card->driver, driver_name); | ||
539 | strcpy(card->shortname, properties->name); | ||
540 | sprintf(card->longname, "Line 6 %s at USB %s", properties->name, | ||
541 | dev_name(line6->ifcdev)); | ||
542 | card->private_free = line6_destruct; | ||
543 | |||
544 | usb_set_intfdata(interface, line6); | ||
545 | |||
546 | /* increment reference counters: */ | ||
547 | usb_get_dev(usbdev); | ||
548 | |||
549 | /* initialize device info: */ | ||
550 | dev_info(&interface->dev, "Line 6 %s found\n", properties->name); | ||
551 | |||
552 | /* query interface number */ | ||
553 | interface_number = interface->cur_altsetting->desc.bInterfaceNumber; | ||
554 | |||
555 | ret = usb_set_interface(usbdev, interface_number, | ||
556 | properties->altsetting); | ||
557 | if (ret < 0) { | ||
558 | dev_err(&interface->dev, "set_interface failed\n"); | ||
559 | goto error; | ||
560 | } | ||
561 | |||
562 | line6_get_interval(line6); | ||
563 | |||
564 | if (properties->capabilities & LINE6_CAP_CONTROL) { | ||
565 | ret = line6_init_cap_control(line6); | ||
566 | if (ret < 0) | ||
567 | goto error; | ||
568 | } | ||
569 | |||
570 | /* initialize device data based on device: */ | ||
571 | ret = private_init(line6, id); | ||
572 | if (ret < 0) | ||
573 | goto error; | ||
574 | |||
575 | /* creation of additional special files should go here */ | ||
576 | |||
577 | dev_info(&interface->dev, "Line 6 %s now attached\n", | ||
578 | properties->name); | ||
579 | |||
580 | return 0; | ||
581 | |||
582 | error: | ||
583 | if (line6->disconnect) | ||
584 | line6->disconnect(line6); | ||
585 | snd_card_free(card); | ||
586 | return ret; | ||
587 | } | ||
588 | EXPORT_SYMBOL_GPL(line6_probe); | ||
589 | |||
590 | /* | ||
591 | Line 6 device disconnected. | ||
592 | */ | ||
593 | void line6_disconnect(struct usb_interface *interface) | ||
594 | { | ||
595 | struct usb_line6 *line6 = usb_get_intfdata(interface); | ||
596 | struct usb_device *usbdev = interface_to_usbdev(interface); | ||
597 | |||
598 | if (!line6) | ||
599 | return; | ||
600 | |||
601 | if (WARN_ON(usbdev != line6->usbdev)) | ||
602 | return; | ||
603 | |||
604 | if (line6->urb_listen != NULL) | ||
605 | line6_stop_listen(line6); | ||
606 | |||
607 | snd_card_disconnect(line6->card); | ||
608 | if (line6->line6pcm) | ||
609 | line6_pcm_disconnect(line6->line6pcm); | ||
610 | if (line6->disconnect) | ||
611 | line6->disconnect(line6); | ||
612 | |||
613 | dev_info(&interface->dev, "Line 6 %s now disconnected\n", | ||
614 | line6->properties->name); | ||
615 | |||
616 | /* make sure the device isn't destructed twice: */ | ||
617 | usb_set_intfdata(interface, NULL); | ||
618 | |||
619 | snd_card_free_when_closed(line6->card); | ||
620 | } | ||
621 | EXPORT_SYMBOL_GPL(line6_disconnect); | ||
622 | |||
623 | #ifdef CONFIG_PM | ||
624 | |||
625 | /* | ||
626 | Suspend Line 6 device. | ||
627 | */ | ||
628 | int line6_suspend(struct usb_interface *interface, pm_message_t message) | ||
629 | { | ||
630 | struct usb_line6 *line6 = usb_get_intfdata(interface); | ||
631 | struct snd_line6_pcm *line6pcm = line6->line6pcm; | ||
632 | |||
633 | snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); | ||
634 | |||
635 | if (line6->properties->capabilities & LINE6_CAP_CONTROL) | ||
636 | line6_stop_listen(line6); | ||
637 | |||
638 | if (line6pcm != NULL) { | ||
639 | snd_pcm_suspend_all(line6pcm->pcm); | ||
640 | line6pcm->flags = 0; | ||
641 | } | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | EXPORT_SYMBOL_GPL(line6_suspend); | ||
646 | |||
647 | /* | ||
648 | Resume Line 6 device. | ||
649 | */ | ||
650 | int line6_resume(struct usb_interface *interface) | ||
651 | { | ||
652 | struct usb_line6 *line6 = usb_get_intfdata(interface); | ||
653 | |||
654 | if (line6->properties->capabilities & LINE6_CAP_CONTROL) | ||
655 | line6_start_listen(line6); | ||
656 | |||
657 | snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); | ||
658 | return 0; | ||
659 | } | ||
660 | EXPORT_SYMBOL_GPL(line6_resume); | ||
661 | |||
662 | #endif /* CONFIG_PM */ | ||
663 | |||
664 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
665 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
666 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h new file mode 100644 index 000000000000..5d20294d64f4 --- /dev/null +++ b/sound/usb/line6/driver.h | |||
@@ -0,0 +1,181 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 USB_INTERVALS_PER_SECOND 1000 | ||
22 | |||
23 | /* Fallback USB interval and max packet size values */ | ||
24 | #define LINE6_FALLBACK_INTERVAL 10 | ||
25 | #define LINE6_FALLBACK_MAXPACKETSIZE 16 | ||
26 | |||
27 | #define LINE6_TIMEOUT 1 | ||
28 | #define LINE6_BUFSIZE_LISTEN 32 | ||
29 | #define LINE6_MESSAGE_MAXLEN 256 | ||
30 | |||
31 | /* | ||
32 | Line 6 MIDI control commands | ||
33 | */ | ||
34 | #define LINE6_PARAM_CHANGE 0xb0 | ||
35 | #define LINE6_PROGRAM_CHANGE 0xc0 | ||
36 | #define LINE6_SYSEX_BEGIN 0xf0 | ||
37 | #define LINE6_SYSEX_END 0xf7 | ||
38 | #define LINE6_RESET 0xff | ||
39 | |||
40 | /* | ||
41 | MIDI channel for messages initiated by the host | ||
42 | (and eventually echoed back by the device) | ||
43 | */ | ||
44 | #define LINE6_CHANNEL_HOST 0x00 | ||
45 | |||
46 | /* | ||
47 | MIDI channel for messages initiated by the device | ||
48 | */ | ||
49 | #define LINE6_CHANNEL_DEVICE 0x02 | ||
50 | |||
51 | #define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */ | ||
52 | |||
53 | #define LINE6_CHANNEL_MASK 0x0f | ||
54 | |||
55 | #define CHECK_STARTUP_PROGRESS(x, n) \ | ||
56 | do { \ | ||
57 | if ((x) >= (n)) \ | ||
58 | return; \ | ||
59 | x = (n); \ | ||
60 | } while (0) | ||
61 | |||
62 | extern const unsigned char line6_midi_id[3]; | ||
63 | |||
64 | static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; | ||
65 | static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; | ||
66 | |||
67 | /* | ||
68 | Common properties of Line 6 devices. | ||
69 | */ | ||
70 | struct line6_properties { | ||
71 | /* Card id string (maximum 16 characters). | ||
72 | * This can be used to address the device in ALSA programs as | ||
73 | * "default:CARD=<id>" | ||
74 | */ | ||
75 | const char *id; | ||
76 | |||
77 | /* Card short name (maximum 32 characters) */ | ||
78 | const char *name; | ||
79 | |||
80 | /* Bit vector defining this device's capabilities in line6usb driver */ | ||
81 | int capabilities; | ||
82 | |||
83 | int altsetting; | ||
84 | |||
85 | unsigned ep_ctrl_r; | ||
86 | unsigned ep_ctrl_w; | ||
87 | unsigned ep_audio_r; | ||
88 | unsigned ep_audio_w; | ||
89 | }; | ||
90 | |||
91 | /* Capability bits */ | ||
92 | enum { | ||
93 | /* device supports settings parameter via USB */ | ||
94 | LINE6_CAP_CONTROL = 1 << 0, | ||
95 | /* device supports PCM input/output via USB */ | ||
96 | LINE6_CAP_PCM = 1 << 1, | ||
97 | /* device support hardware monitoring */ | ||
98 | LINE6_CAP_HWMON = 1 << 2, | ||
99 | }; | ||
100 | |||
101 | /* | ||
102 | Common data shared by all Line 6 devices. | ||
103 | Corresponds to a pair of USB endpoints. | ||
104 | */ | ||
105 | struct usb_line6 { | ||
106 | /* USB device */ | ||
107 | struct usb_device *usbdev; | ||
108 | |||
109 | /* Properties */ | ||
110 | const struct line6_properties *properties; | ||
111 | |||
112 | /* Interval (ms) */ | ||
113 | int interval; | ||
114 | |||
115 | /* Maximum size of USB packet */ | ||
116 | int max_packet_size; | ||
117 | |||
118 | /* Device representing the USB interface */ | ||
119 | struct device *ifcdev; | ||
120 | |||
121 | /* Line 6 sound card data structure. | ||
122 | * Each device has at least MIDI or PCM. | ||
123 | */ | ||
124 | struct snd_card *card; | ||
125 | |||
126 | /* Line 6 PCM device data structure */ | ||
127 | struct snd_line6_pcm *line6pcm; | ||
128 | |||
129 | /* Line 6 MIDI device data structure */ | ||
130 | struct snd_line6_midi *line6midi; | ||
131 | |||
132 | /* URB for listening to PODxt Pro control endpoint */ | ||
133 | struct urb *urb_listen; | ||
134 | |||
135 | /* Buffer for listening to PODxt Pro control endpoint */ | ||
136 | unsigned char *buffer_listen; | ||
137 | |||
138 | /* Buffer for message to be processed */ | ||
139 | unsigned char *buffer_message; | ||
140 | |||
141 | /* Length of message to be processed */ | ||
142 | int message_length; | ||
143 | |||
144 | void (*process_message)(struct usb_line6 *); | ||
145 | void (*disconnect)(struct usb_line6 *line6); | ||
146 | }; | ||
147 | |||
148 | extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, | ||
149 | int code2, int size); | ||
150 | extern int line6_read_data(struct usb_line6 *line6, int address, void *data, | ||
151 | size_t datalen); | ||
152 | extern int line6_read_serial_number(struct usb_line6 *line6, | ||
153 | u32 *serial_number); | ||
154 | extern int line6_send_raw_message_async(struct usb_line6 *line6, | ||
155 | const char *buffer, int size); | ||
156 | extern int line6_send_sysex_message(struct usb_line6 *line6, | ||
157 | const char *buffer, int size); | ||
158 | extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, | ||
159 | const char *buf, size_t count); | ||
160 | extern void line6_start_timer(struct timer_list *timer, unsigned long msecs, | ||
161 | void (*function)(unsigned long), | ||
162 | unsigned long data); | ||
163 | extern int line6_version_request_async(struct usb_line6 *line6); | ||
164 | extern int line6_write_data(struct usb_line6 *line6, int address, void *data, | ||
165 | size_t datalen); | ||
166 | |||
167 | int line6_probe(struct usb_interface *interface, | ||
168 | const struct usb_device_id *id, | ||
169 | const char *driver_name, | ||
170 | const struct line6_properties *properties, | ||
171 | int (*private_init)(struct usb_line6 *, const struct usb_device_id *id), | ||
172 | size_t data_size); | ||
173 | |||
174 | void line6_disconnect(struct usb_interface *interface); | ||
175 | |||
176 | #ifdef CONFIG_PM | ||
177 | int line6_suspend(struct usb_interface *interface, pm_message_t message); | ||
178 | int line6_resume(struct usb_interface *interface); | ||
179 | #endif | ||
180 | |||
181 | #endif | ||
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c new file mode 100644 index 000000000000..cebea9b7f769 --- /dev/null +++ b/sound/usb/line6/midi.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 <linux/export.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/rawmidi.h> | ||
17 | |||
18 | #include "driver.h" | ||
19 | #include "midi.h" | ||
20 | |||
21 | #define line6_rawmidi_substream_midi(substream) \ | ||
22 | ((struct snd_line6_midi *)((substream)->rmidi->private_data)) | ||
23 | |||
24 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, | ||
25 | int length); | ||
26 | |||
27 | /* | ||
28 | Pass data received via USB to MIDI. | ||
29 | */ | ||
30 | void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, | ||
31 | int length) | ||
32 | { | ||
33 | if (line6->line6midi->substream_receive) | ||
34 | snd_rawmidi_receive(line6->line6midi->substream_receive, | ||
35 | data, length); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | Read data from MIDI buffer and transmit them via USB. | ||
40 | */ | ||
41 | static void line6_midi_transmit(struct snd_rawmidi_substream *substream) | ||
42 | { | ||
43 | struct usb_line6 *line6 = | ||
44 | line6_rawmidi_substream_midi(substream)->line6; | ||
45 | struct snd_line6_midi *line6midi = line6->line6midi; | ||
46 | struct midi_buffer *mb = &line6midi->midibuf_out; | ||
47 | unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE]; | ||
48 | int req, done; | ||
49 | |||
50 | for (;;) { | ||
51 | req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); | ||
52 | done = snd_rawmidi_transmit_peek(substream, chunk, req); | ||
53 | |||
54 | if (done == 0) | ||
55 | break; | ||
56 | |||
57 | line6_midibuf_write(mb, chunk, done); | ||
58 | snd_rawmidi_transmit_ack(substream, done); | ||
59 | } | ||
60 | |||
61 | for (;;) { | ||
62 | done = line6_midibuf_read(mb, chunk, | ||
63 | LINE6_FALLBACK_MAXPACKETSIZE); | ||
64 | |||
65 | if (done == 0) | ||
66 | break; | ||
67 | |||
68 | send_midi_async(line6, chunk, done); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | Notification of completion of MIDI transmission. | ||
74 | */ | ||
75 | static void midi_sent(struct urb *urb) | ||
76 | { | ||
77 | unsigned long flags; | ||
78 | int status; | ||
79 | int num; | ||
80 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; | ||
81 | |||
82 | status = urb->status; | ||
83 | kfree(urb->transfer_buffer); | ||
84 | usb_free_urb(urb); | ||
85 | |||
86 | if (status == -ESHUTDOWN) | ||
87 | return; | ||
88 | |||
89 | spin_lock_irqsave(&line6->line6midi->lock, flags); | ||
90 | num = --line6->line6midi->num_active_send_urbs; | ||
91 | |||
92 | if (num == 0) { | ||
93 | line6_midi_transmit(line6->line6midi->substream_transmit); | ||
94 | num = line6->line6midi->num_active_send_urbs; | ||
95 | } | ||
96 | |||
97 | if (num == 0) | ||
98 | wake_up(&line6->line6midi->send_wait); | ||
99 | |||
100 | spin_unlock_irqrestore(&line6->line6midi->lock, flags); | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | Send an asynchronous MIDI message. | ||
105 | Assumes that line6->line6midi->lock is held | ||
106 | (i.e., this function is serialized). | ||
107 | */ | ||
108 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, | ||
109 | int length) | ||
110 | { | ||
111 | struct urb *urb; | ||
112 | int retval; | ||
113 | unsigned char *transfer_buffer; | ||
114 | |||
115 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
116 | |||
117 | if (urb == NULL) | ||
118 | return -ENOMEM; | ||
119 | |||
120 | transfer_buffer = kmemdup(data, length, GFP_ATOMIC); | ||
121 | |||
122 | if (transfer_buffer == NULL) { | ||
123 | usb_free_urb(urb); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | |||
127 | usb_fill_int_urb(urb, line6->usbdev, | ||
128 | usb_sndbulkpipe(line6->usbdev, | ||
129 | line6->properties->ep_ctrl_w), | ||
130 | transfer_buffer, length, midi_sent, line6, | ||
131 | line6->interval); | ||
132 | urb->actual_length = 0; | ||
133 | retval = usb_submit_urb(urb, GFP_ATOMIC); | ||
134 | |||
135 | if (retval < 0) { | ||
136 | dev_err(line6->ifcdev, "usb_submit_urb failed\n"); | ||
137 | usb_free_urb(urb); | ||
138 | return retval; | ||
139 | } | ||
140 | |||
141 | ++line6->line6midi->num_active_send_urbs; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int line6_midi_output_open(struct snd_rawmidi_substream *substream) | ||
146 | { | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int line6_midi_output_close(struct snd_rawmidi_substream *substream) | ||
151 | { | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, | ||
156 | int up) | ||
157 | { | ||
158 | unsigned long flags; | ||
159 | struct usb_line6 *line6 = | ||
160 | line6_rawmidi_substream_midi(substream)->line6; | ||
161 | |||
162 | line6->line6midi->substream_transmit = substream; | ||
163 | spin_lock_irqsave(&line6->line6midi->lock, flags); | ||
164 | |||
165 | if (line6->line6midi->num_active_send_urbs == 0) | ||
166 | line6_midi_transmit(substream); | ||
167 | |||
168 | spin_unlock_irqrestore(&line6->line6midi->lock, flags); | ||
169 | } | ||
170 | |||
171 | static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) | ||
172 | { | ||
173 | struct usb_line6 *line6 = | ||
174 | line6_rawmidi_substream_midi(substream)->line6; | ||
175 | struct snd_line6_midi *midi = line6->line6midi; | ||
176 | |||
177 | wait_event_interruptible(midi->send_wait, | ||
178 | midi->num_active_send_urbs == 0); | ||
179 | } | ||
180 | |||
181 | static int line6_midi_input_open(struct snd_rawmidi_substream *substream) | ||
182 | { | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int line6_midi_input_close(struct snd_rawmidi_substream *substream) | ||
187 | { | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, | ||
192 | int up) | ||
193 | { | ||
194 | struct usb_line6 *line6 = | ||
195 | line6_rawmidi_substream_midi(substream)->line6; | ||
196 | |||
197 | if (up) | ||
198 | line6->line6midi->substream_receive = substream; | ||
199 | else | ||
200 | line6->line6midi->substream_receive = NULL; | ||
201 | } | ||
202 | |||
203 | static struct snd_rawmidi_ops line6_midi_output_ops = { | ||
204 | .open = line6_midi_output_open, | ||
205 | .close = line6_midi_output_close, | ||
206 | .trigger = line6_midi_output_trigger, | ||
207 | .drain = line6_midi_output_drain, | ||
208 | }; | ||
209 | |||
210 | static struct snd_rawmidi_ops line6_midi_input_ops = { | ||
211 | .open = line6_midi_input_open, | ||
212 | .close = line6_midi_input_close, | ||
213 | .trigger = line6_midi_input_trigger, | ||
214 | }; | ||
215 | |||
216 | /* Create a MIDI device */ | ||
217 | static int snd_line6_new_midi(struct usb_line6 *line6, | ||
218 | struct snd_rawmidi **rmidi_ret) | ||
219 | { | ||
220 | struct snd_rawmidi *rmidi; | ||
221 | int err; | ||
222 | |||
223 | err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret); | ||
224 | if (err < 0) | ||
225 | return err; | ||
226 | |||
227 | rmidi = *rmidi_ret; | ||
228 | strcpy(rmidi->id, line6->properties->id); | ||
229 | strcpy(rmidi->name, line6->properties->name); | ||
230 | |||
231 | rmidi->info_flags = | ||
232 | SNDRV_RAWMIDI_INFO_OUTPUT | | ||
233 | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; | ||
234 | |||
235 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
236 | &line6_midi_output_ops); | ||
237 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
238 | &line6_midi_input_ops); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | /* MIDI device destructor */ | ||
243 | static void snd_line6_midi_free(struct snd_rawmidi *rmidi) | ||
244 | { | ||
245 | struct snd_line6_midi *line6midi = rmidi->private_data; | ||
246 | |||
247 | line6_midibuf_destroy(&line6midi->midibuf_in); | ||
248 | line6_midibuf_destroy(&line6midi->midibuf_out); | ||
249 | kfree(line6midi); | ||
250 | } | ||
251 | |||
252 | /* | ||
253 | Initialize the Line 6 MIDI subsystem. | ||
254 | */ | ||
255 | int line6_init_midi(struct usb_line6 *line6) | ||
256 | { | ||
257 | int err; | ||
258 | struct snd_rawmidi *rmidi; | ||
259 | struct snd_line6_midi *line6midi; | ||
260 | |||
261 | if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { | ||
262 | /* skip MIDI initialization and report success */ | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | err = snd_line6_new_midi(line6, &rmidi); | ||
267 | if (err < 0) | ||
268 | return err; | ||
269 | |||
270 | line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); | ||
271 | if (!line6midi) | ||
272 | return -ENOMEM; | ||
273 | |||
274 | rmidi->private_data = line6midi; | ||
275 | rmidi->private_free = snd_line6_midi_free; | ||
276 | |||
277 | init_waitqueue_head(&line6midi->send_wait); | ||
278 | spin_lock_init(&line6midi->lock); | ||
279 | line6midi->line6 = line6; | ||
280 | |||
281 | err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); | ||
282 | if (err < 0) | ||
283 | return err; | ||
284 | |||
285 | err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); | ||
286 | if (err < 0) | ||
287 | return err; | ||
288 | |||
289 | line6->line6midi = line6midi; | ||
290 | return 0; | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(line6_init_midi); | ||
diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h new file mode 100644 index 000000000000..cf82d69e2747 --- /dev/null +++ b/sound/usb/line6/midi.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 | /* Pointer back to the Line 6 driver data structure */ | ||
23 | struct usb_line6 *line6; | ||
24 | |||
25 | /* MIDI substream for receiving (or NULL if not active) */ | ||
26 | struct snd_rawmidi_substream *substream_receive; | ||
27 | |||
28 | /* MIDI substream for transmitting (or NULL if not active) */ | ||
29 | struct snd_rawmidi_substream *substream_transmit; | ||
30 | |||
31 | /* Number of currently active MIDI send URBs */ | ||
32 | int num_active_send_urbs; | ||
33 | |||
34 | /* Spin lock to protect MIDI buffer handling */ | ||
35 | spinlock_t lock; | ||
36 | |||
37 | /* Wait queue for MIDI transmission */ | ||
38 | wait_queue_head_t send_wait; | ||
39 | |||
40 | /* Buffer for incoming MIDI stream */ | ||
41 | struct midi_buffer midibuf_in; | ||
42 | |||
43 | /* Buffer for outgoing MIDI stream */ | ||
44 | struct midi_buffer midibuf_out; | ||
45 | }; | ||
46 | |||
47 | extern int line6_init_midi(struct usb_line6 *line6); | ||
48 | extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, | ||
49 | int length); | ||
50 | |||
51 | #endif | ||
diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c new file mode 100644 index 000000000000..36a610ba342e --- /dev/null +++ b/sound/usb/line6/midibuf.c | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 Line 6 | ||
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 | int line6_midibuf_bytes_free(struct midi_buffer *this) | ||
71 | { | ||
72 | return | ||
73 | midibuf_is_full(this) ? | ||
74 | 0 : | ||
75 | (this->pos_read - this->pos_write + this->size - 1) % this->size + | ||
76 | 1; | ||
77 | } | ||
78 | |||
79 | int line6_midibuf_bytes_used(struct midi_buffer *this) | ||
80 | { | ||
81 | return | ||
82 | midibuf_is_empty(this) ? | ||
83 | 0 : | ||
84 | (this->pos_write - this->pos_read + this->size - 1) % this->size + | ||
85 | 1; | ||
86 | } | ||
87 | |||
88 | int line6_midibuf_write(struct midi_buffer *this, unsigned char *data, | ||
89 | int length) | ||
90 | { | ||
91 | int bytes_free; | ||
92 | int length1, length2; | ||
93 | int skip_active_sense = 0; | ||
94 | |||
95 | if (midibuf_is_full(this) || (length <= 0)) | ||
96 | return 0; | ||
97 | |||
98 | /* skip trailing active sense */ | ||
99 | if (data[length - 1] == 0xfe) { | ||
100 | --length; | ||
101 | skip_active_sense = 1; | ||
102 | } | ||
103 | |||
104 | bytes_free = line6_midibuf_bytes_free(this); | ||
105 | |||
106 | if (length > bytes_free) | ||
107 | length = bytes_free; | ||
108 | |||
109 | if (length > 0) { | ||
110 | length1 = this->size - this->pos_write; | ||
111 | |||
112 | if (length < length1) { | ||
113 | /* no buffer wraparound */ | ||
114 | memcpy(this->buf + this->pos_write, data, length); | ||
115 | this->pos_write += length; | ||
116 | } else { | ||
117 | /* buffer wraparound */ | ||
118 | length2 = length - length1; | ||
119 | memcpy(this->buf + this->pos_write, data, length1); | ||
120 | memcpy(this->buf, data + length1, length2); | ||
121 | this->pos_write = length2; | ||
122 | } | ||
123 | |||
124 | if (this->pos_write == this->pos_read) | ||
125 | this->full = 1; | ||
126 | } | ||
127 | |||
128 | return length + skip_active_sense; | ||
129 | } | ||
130 | |||
131 | int line6_midibuf_read(struct midi_buffer *this, unsigned char *data, | ||
132 | int length) | ||
133 | { | ||
134 | int bytes_used; | ||
135 | int length1, length2; | ||
136 | int command; | ||
137 | int midi_length; | ||
138 | int repeat = 0; | ||
139 | int i; | ||
140 | |||
141 | /* we need to be able to store at least a 3 byte MIDI message */ | ||
142 | if (length < 3) | ||
143 | return -EINVAL; | ||
144 | |||
145 | if (midibuf_is_empty(this)) | ||
146 | return 0; | ||
147 | |||
148 | bytes_used = line6_midibuf_bytes_used(this); | ||
149 | |||
150 | if (length > bytes_used) | ||
151 | length = bytes_used; | ||
152 | |||
153 | length1 = this->size - this->pos_read; | ||
154 | |||
155 | /* check MIDI command length */ | ||
156 | command = this->buf[this->pos_read]; | ||
157 | |||
158 | if (command & 0x80) { | ||
159 | midi_length = midibuf_message_length(command); | ||
160 | this->command_prev = command; | ||
161 | } else { | ||
162 | if (this->command_prev > 0) { | ||
163 | int midi_length_prev = | ||
164 | midibuf_message_length(this->command_prev); | ||
165 | |||
166 | if (midi_length_prev > 0) { | ||
167 | midi_length = midi_length_prev - 1; | ||
168 | repeat = 1; | ||
169 | } else | ||
170 | midi_length = -1; | ||
171 | } else | ||
172 | midi_length = -1; | ||
173 | } | ||
174 | |||
175 | if (midi_length < 0) { | ||
176 | /* search for end of message */ | ||
177 | if (length < length1) { | ||
178 | /* no buffer wraparound */ | ||
179 | for (i = 1; i < length; ++i) | ||
180 | if (this->buf[this->pos_read + i] & 0x80) | ||
181 | break; | ||
182 | |||
183 | midi_length = i; | ||
184 | } else { | ||
185 | /* buffer wraparound */ | ||
186 | length2 = length - length1; | ||
187 | |||
188 | for (i = 1; i < length1; ++i) | ||
189 | if (this->buf[this->pos_read + i] & 0x80) | ||
190 | break; | ||
191 | |||
192 | if (i < length1) | ||
193 | midi_length = i; | ||
194 | else { | ||
195 | for (i = 0; i < length2; ++i) | ||
196 | if (this->buf[i] & 0x80) | ||
197 | break; | ||
198 | |||
199 | midi_length = length1 + i; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | if (midi_length == length) | ||
204 | midi_length = -1; /* end of message not found */ | ||
205 | } | ||
206 | |||
207 | if (midi_length < 0) { | ||
208 | if (!this->split) | ||
209 | return 0; /* command is not yet complete */ | ||
210 | } else { | ||
211 | if (length < midi_length) | ||
212 | return 0; /* command is not yet complete */ | ||
213 | |||
214 | length = midi_length; | ||
215 | } | ||
216 | |||
217 | if (length < length1) { | ||
218 | /* no buffer wraparound */ | ||
219 | memcpy(data + repeat, this->buf + this->pos_read, length); | ||
220 | this->pos_read += length; | ||
221 | } else { | ||
222 | /* buffer wraparound */ | ||
223 | length2 = length - length1; | ||
224 | memcpy(data + repeat, this->buf + this->pos_read, length1); | ||
225 | memcpy(data + repeat + length1, this->buf, length2); | ||
226 | this->pos_read = length2; | ||
227 | } | ||
228 | |||
229 | if (repeat) | ||
230 | data[0] = this->command_prev; | ||
231 | |||
232 | this->full = 0; | ||
233 | return length + repeat; | ||
234 | } | ||
235 | |||
236 | int line6_midibuf_ignore(struct midi_buffer *this, int length) | ||
237 | { | ||
238 | int bytes_used = line6_midibuf_bytes_used(this); | ||
239 | |||
240 | if (length > bytes_used) | ||
241 | length = bytes_used; | ||
242 | |||
243 | this->pos_read = (this->pos_read + length) % this->size; | ||
244 | this->full = 0; | ||
245 | return length; | ||
246 | } | ||
247 | |||
248 | void line6_midibuf_destroy(struct midi_buffer *this) | ||
249 | { | ||
250 | kfree(this->buf); | ||
251 | this->buf = NULL; | ||
252 | } | ||
diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h new file mode 100644 index 000000000000..6ea21ffb6627 --- /dev/null +++ b/sound/usb/line6/midibuf.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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_write(struct midi_buffer *mb, unsigned char *data, | ||
33 | int length); | ||
34 | |||
35 | #endif | ||
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c new file mode 100644 index 000000000000..8461d6bf992f --- /dev/null +++ b/sound/usb/line6/pcm.c | |||
@@ -0,0 +1,588 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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/export.h> | ||
14 | #include <sound/core.h> | ||
15 | #include <sound/control.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | |||
19 | #include "capture.h" | ||
20 | #include "driver.h" | ||
21 | #include "playback.h" | ||
22 | |||
23 | /* impulse response volume controls */ | ||
24 | static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol, | ||
25 | struct snd_ctl_elem_info *uinfo) | ||
26 | { | ||
27 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
28 | uinfo->count = 1; | ||
29 | uinfo->value.integer.min = 0; | ||
30 | uinfo->value.integer.max = 255; | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol, | ||
35 | struct snd_ctl_elem_value *ucontrol) | ||
36 | { | ||
37 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
38 | |||
39 | ucontrol->value.integer.value[0] = line6pcm->impulse_volume; | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol, | ||
44 | struct snd_ctl_elem_value *ucontrol) | ||
45 | { | ||
46 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
47 | int value = ucontrol->value.integer.value[0]; | ||
48 | int err; | ||
49 | |||
50 | if (line6pcm->impulse_volume == value) | ||
51 | return 0; | ||
52 | |||
53 | line6pcm->impulse_volume = value; | ||
54 | if (value > 0) { | ||
55 | err = line6_pcm_acquire(line6pcm, LINE6_STREAM_IMPULSE); | ||
56 | if (err < 0) { | ||
57 | line6pcm->impulse_volume = 0; | ||
58 | line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); | ||
59 | return err; | ||
60 | } | ||
61 | } else { | ||
62 | line6_pcm_release(line6pcm, LINE6_STREAM_IMPULSE); | ||
63 | } | ||
64 | return 1; | ||
65 | } | ||
66 | |||
67 | /* impulse response period controls */ | ||
68 | static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol, | ||
69 | struct snd_ctl_elem_info *uinfo) | ||
70 | { | ||
71 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
72 | uinfo->count = 1; | ||
73 | uinfo->value.integer.min = 0; | ||
74 | uinfo->value.integer.max = 2000; | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol, | ||
79 | struct snd_ctl_elem_value *ucontrol) | ||
80 | { | ||
81 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
82 | |||
83 | ucontrol->value.integer.value[0] = line6pcm->impulse_period; | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol, | ||
88 | struct snd_ctl_elem_value *ucontrol) | ||
89 | { | ||
90 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
91 | int value = ucontrol->value.integer.value[0]; | ||
92 | |||
93 | if (line6pcm->impulse_period == value) | ||
94 | return 0; | ||
95 | |||
96 | line6pcm->impulse_period = value; | ||
97 | return 1; | ||
98 | } | ||
99 | |||
100 | /* | ||
101 | Unlink all currently active URBs. | ||
102 | */ | ||
103 | static void line6_unlink_audio_urbs(struct snd_line6_pcm *line6pcm, | ||
104 | struct line6_pcm_stream *pcms) | ||
105 | { | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; i < LINE6_ISO_BUFFERS; i++) { | ||
109 | if (test_bit(i, &pcms->active_urbs)) { | ||
110 | if (!test_and_set_bit(i, &pcms->unlink_urbs)) | ||
111 | usb_unlink_urb(pcms->urbs[i]); | ||
112 | } | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | Wait until unlinking of all currently active URBs has been finished. | ||
118 | */ | ||
119 | static void line6_wait_clear_audio_urbs(struct snd_line6_pcm *line6pcm, | ||
120 | struct line6_pcm_stream *pcms) | ||
121 | { | ||
122 | int timeout = HZ; | ||
123 | int i; | ||
124 | int alive; | ||
125 | |||
126 | do { | ||
127 | alive = 0; | ||
128 | for (i = 0; i < LINE6_ISO_BUFFERS; i++) { | ||
129 | if (test_bit(i, &pcms->active_urbs)) | ||
130 | alive++; | ||
131 | } | ||
132 | if (!alive) | ||
133 | break; | ||
134 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
135 | schedule_timeout(1); | ||
136 | } while (--timeout > 0); | ||
137 | if (alive) | ||
138 | dev_err(line6pcm->line6->ifcdev, | ||
139 | "timeout: still %d active urbs..\n", alive); | ||
140 | } | ||
141 | |||
142 | static inline struct line6_pcm_stream * | ||
143 | get_stream(struct snd_line6_pcm *line6pcm, int direction) | ||
144 | { | ||
145 | return (direction == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
146 | &line6pcm->out : &line6pcm->in; | ||
147 | } | ||
148 | |||
149 | /* allocate a buffer if not opened yet; | ||
150 | * call this in line6pcm.state_change mutex | ||
151 | */ | ||
152 | static int line6_buffer_acquire(struct snd_line6_pcm *line6pcm, | ||
153 | struct line6_pcm_stream *pstr, int type) | ||
154 | { | ||
155 | /* Invoked multiple times in a row so allocate once only */ | ||
156 | if (!test_and_set_bit(type, &pstr->opened) && !pstr->buffer) { | ||
157 | pstr->buffer = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * | ||
158 | line6pcm->max_packet_size, GFP_KERNEL); | ||
159 | if (!pstr->buffer) | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | /* free a buffer if all streams are closed; | ||
166 | * call this in line6pcm.state_change mutex | ||
167 | */ | ||
168 | static void line6_buffer_release(struct snd_line6_pcm *line6pcm, | ||
169 | struct line6_pcm_stream *pstr, int type) | ||
170 | { | ||
171 | |||
172 | clear_bit(type, &pstr->opened); | ||
173 | if (!pstr->opened) { | ||
174 | line6_wait_clear_audio_urbs(line6pcm, pstr); | ||
175 | kfree(pstr->buffer); | ||
176 | pstr->buffer = NULL; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* start a PCM stream */ | ||
181 | static int line6_stream_start(struct snd_line6_pcm *line6pcm, int direction, | ||
182 | int type) | ||
183 | { | ||
184 | unsigned long flags; | ||
185 | struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); | ||
186 | int ret = 0; | ||
187 | |||
188 | spin_lock_irqsave(&pstr->lock, flags); | ||
189 | if (!test_and_set_bit(type, &pstr->running)) { | ||
190 | if (pstr->active_urbs || pstr->unlink_urbs) { | ||
191 | ret = -EBUSY; | ||
192 | goto error; | ||
193 | } | ||
194 | |||
195 | pstr->count = 0; | ||
196 | /* Submit all currently available URBs */ | ||
197 | if (direction == SNDRV_PCM_STREAM_PLAYBACK) | ||
198 | ret = line6_submit_audio_out_all_urbs(line6pcm); | ||
199 | else | ||
200 | ret = line6_submit_audio_in_all_urbs(line6pcm); | ||
201 | } | ||
202 | error: | ||
203 | if (ret < 0) | ||
204 | clear_bit(type, &pstr->running); | ||
205 | spin_unlock_irqrestore(&pstr->lock, flags); | ||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | /* stop a PCM stream; this doesn't sync with the unlinked URBs */ | ||
210 | static void line6_stream_stop(struct snd_line6_pcm *line6pcm, int direction, | ||
211 | int type) | ||
212 | { | ||
213 | unsigned long flags; | ||
214 | struct line6_pcm_stream *pstr = get_stream(line6pcm, direction); | ||
215 | |||
216 | spin_lock_irqsave(&pstr->lock, flags); | ||
217 | clear_bit(type, &pstr->running); | ||
218 | if (!pstr->running) { | ||
219 | line6_unlink_audio_urbs(line6pcm, pstr); | ||
220 | if (direction == SNDRV_PCM_STREAM_CAPTURE) { | ||
221 | line6pcm->prev_fbuf = NULL; | ||
222 | line6pcm->prev_fsize = 0; | ||
223 | } | ||
224 | } | ||
225 | spin_unlock_irqrestore(&pstr->lock, flags); | ||
226 | } | ||
227 | |||
228 | /* common PCM trigger callback */ | ||
229 | int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd) | ||
230 | { | ||
231 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
232 | struct snd_pcm_substream *s; | ||
233 | int err; | ||
234 | |||
235 | clear_bit(LINE6_FLAG_PREPARED, &line6pcm->flags); | ||
236 | |||
237 | snd_pcm_group_for_each_entry(s, substream) { | ||
238 | if (s->pcm->card != substream->pcm->card) | ||
239 | continue; | ||
240 | |||
241 | switch (cmd) { | ||
242 | case SNDRV_PCM_TRIGGER_START: | ||
243 | case SNDRV_PCM_TRIGGER_RESUME: | ||
244 | err = line6_stream_start(line6pcm, s->stream, | ||
245 | LINE6_STREAM_PCM); | ||
246 | if (err < 0) | ||
247 | return err; | ||
248 | break; | ||
249 | |||
250 | case SNDRV_PCM_TRIGGER_STOP: | ||
251 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
252 | line6_stream_stop(line6pcm, s->stream, | ||
253 | LINE6_STREAM_PCM); | ||
254 | break; | ||
255 | |||
256 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
257 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
258 | return -EINVAL; | ||
259 | set_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); | ||
260 | break; | ||
261 | |||
262 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
263 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
264 | return -EINVAL; | ||
265 | clear_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags); | ||
266 | break; | ||
267 | |||
268 | default: | ||
269 | return -EINVAL; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | /* common PCM pointer callback */ | ||
277 | snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream) | ||
278 | { | ||
279 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
280 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
281 | |||
282 | return pstr->pos_done; | ||
283 | } | ||
284 | |||
285 | /* Acquire and start duplex streams: | ||
286 | * type is either LINE6_STREAM_IMPULSE or LINE6_STREAM_MONITOR | ||
287 | */ | ||
288 | int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type) | ||
289 | { | ||
290 | struct line6_pcm_stream *pstr; | ||
291 | int ret = 0, dir; | ||
292 | |||
293 | mutex_lock(&line6pcm->state_mutex); | ||
294 | for (dir = 0; dir < 2; dir++) { | ||
295 | pstr = get_stream(line6pcm, dir); | ||
296 | ret = line6_buffer_acquire(line6pcm, pstr, type); | ||
297 | if (ret < 0) | ||
298 | goto error; | ||
299 | if (!pstr->running) | ||
300 | line6_wait_clear_audio_urbs(line6pcm, pstr); | ||
301 | } | ||
302 | for (dir = 0; dir < 2; dir++) { | ||
303 | ret = line6_stream_start(line6pcm, dir, type); | ||
304 | if (ret < 0) | ||
305 | goto error; | ||
306 | } | ||
307 | error: | ||
308 | mutex_unlock(&line6pcm->state_mutex); | ||
309 | if (ret < 0) | ||
310 | line6_pcm_release(line6pcm, type); | ||
311 | return ret; | ||
312 | } | ||
313 | EXPORT_SYMBOL_GPL(line6_pcm_acquire); | ||
314 | |||
315 | /* Stop and release duplex streams */ | ||
316 | void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type) | ||
317 | { | ||
318 | struct line6_pcm_stream *pstr; | ||
319 | int dir; | ||
320 | |||
321 | mutex_lock(&line6pcm->state_mutex); | ||
322 | for (dir = 0; dir < 2; dir++) | ||
323 | line6_stream_stop(line6pcm, dir, type); | ||
324 | for (dir = 0; dir < 2; dir++) { | ||
325 | pstr = get_stream(line6pcm, dir); | ||
326 | line6_buffer_release(line6pcm, pstr, type); | ||
327 | } | ||
328 | mutex_unlock(&line6pcm->state_mutex); | ||
329 | } | ||
330 | EXPORT_SYMBOL_GPL(line6_pcm_release); | ||
331 | |||
332 | /* common PCM hw_params callback */ | ||
333 | int snd_line6_hw_params(struct snd_pcm_substream *substream, | ||
334 | struct snd_pcm_hw_params *hw_params) | ||
335 | { | ||
336 | int ret; | ||
337 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
338 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
339 | |||
340 | mutex_lock(&line6pcm->state_mutex); | ||
341 | ret = line6_buffer_acquire(line6pcm, pstr, LINE6_STREAM_PCM); | ||
342 | if (ret < 0) | ||
343 | goto error; | ||
344 | |||
345 | ret = snd_pcm_lib_malloc_pages(substream, | ||
346 | params_buffer_bytes(hw_params)); | ||
347 | if (ret < 0) { | ||
348 | line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); | ||
349 | goto error; | ||
350 | } | ||
351 | |||
352 | pstr->period = params_period_bytes(hw_params); | ||
353 | error: | ||
354 | mutex_unlock(&line6pcm->state_mutex); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | /* common PCM hw_free callback */ | ||
359 | int snd_line6_hw_free(struct snd_pcm_substream *substream) | ||
360 | { | ||
361 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
362 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
363 | |||
364 | mutex_lock(&line6pcm->state_mutex); | ||
365 | line6_buffer_release(line6pcm, pstr, LINE6_STREAM_PCM); | ||
366 | mutex_unlock(&line6pcm->state_mutex); | ||
367 | return snd_pcm_lib_free_pages(substream); | ||
368 | } | ||
369 | |||
370 | |||
371 | /* control info callback */ | ||
372 | static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol, | ||
373 | struct snd_ctl_elem_info *uinfo) | ||
374 | { | ||
375 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
376 | uinfo->count = 2; | ||
377 | uinfo->value.integer.min = 0; | ||
378 | uinfo->value.integer.max = 256; | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* control get callback */ | ||
383 | static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol, | ||
384 | struct snd_ctl_elem_value *ucontrol) | ||
385 | { | ||
386 | int i; | ||
387 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
388 | |||
389 | for (i = 0; i < 2; i++) | ||
390 | ucontrol->value.integer.value[i] = line6pcm->volume_playback[i]; | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | /* control put callback */ | ||
396 | static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol, | ||
397 | struct snd_ctl_elem_value *ucontrol) | ||
398 | { | ||
399 | int i, changed = 0; | ||
400 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
401 | |||
402 | for (i = 0; i < 2; i++) | ||
403 | if (line6pcm->volume_playback[i] != | ||
404 | ucontrol->value.integer.value[i]) { | ||
405 | line6pcm->volume_playback[i] = | ||
406 | ucontrol->value.integer.value[i]; | ||
407 | changed = 1; | ||
408 | } | ||
409 | |||
410 | return changed; | ||
411 | } | ||
412 | |||
413 | /* control definition */ | ||
414 | static struct snd_kcontrol_new line6_controls[] = { | ||
415 | { | ||
416 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
417 | .name = "PCM Playback Volume", | ||
418 | .info = snd_line6_control_playback_info, | ||
419 | .get = snd_line6_control_playback_get, | ||
420 | .put = snd_line6_control_playback_put | ||
421 | }, | ||
422 | { | ||
423 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
424 | .name = "Impulse Response Volume", | ||
425 | .info = snd_line6_impulse_volume_info, | ||
426 | .get = snd_line6_impulse_volume_get, | ||
427 | .put = snd_line6_impulse_volume_put | ||
428 | }, | ||
429 | { | ||
430 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
431 | .name = "Impulse Response Period", | ||
432 | .info = snd_line6_impulse_period_info, | ||
433 | .get = snd_line6_impulse_period_get, | ||
434 | .put = snd_line6_impulse_period_put | ||
435 | }, | ||
436 | }; | ||
437 | |||
438 | /* | ||
439 | Cleanup the PCM device. | ||
440 | */ | ||
441 | static void cleanup_urbs(struct line6_pcm_stream *pcms) | ||
442 | { | ||
443 | int i; | ||
444 | |||
445 | for (i = 0; i < LINE6_ISO_BUFFERS; i++) { | ||
446 | if (pcms->urbs[i]) { | ||
447 | usb_kill_urb(pcms->urbs[i]); | ||
448 | usb_free_urb(pcms->urbs[i]); | ||
449 | } | ||
450 | } | ||
451 | } | ||
452 | |||
453 | static void line6_cleanup_pcm(struct snd_pcm *pcm) | ||
454 | { | ||
455 | struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm); | ||
456 | |||
457 | cleanup_urbs(&line6pcm->out); | ||
458 | cleanup_urbs(&line6pcm->in); | ||
459 | kfree(line6pcm); | ||
460 | } | ||
461 | |||
462 | /* create a PCM device */ | ||
463 | static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret) | ||
464 | { | ||
465 | struct snd_pcm *pcm; | ||
466 | int err; | ||
467 | |||
468 | err = snd_pcm_new(line6->card, (char *)line6->properties->name, | ||
469 | 0, 1, 1, pcm_ret); | ||
470 | if (err < 0) | ||
471 | return err; | ||
472 | pcm = *pcm_ret; | ||
473 | strcpy(pcm->name, line6->properties->name); | ||
474 | |||
475 | /* set operators */ | ||
476 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
477 | &snd_line6_playback_ops); | ||
478 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops); | ||
479 | |||
480 | /* pre-allocation of buffers */ | ||
481 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, | ||
482 | snd_dma_continuous_data | ||
483 | (GFP_KERNEL), 64 * 1024, | ||
484 | 128 * 1024); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | /* | ||
489 | Sync with PCM stream stops. | ||
490 | */ | ||
491 | void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm) | ||
492 | { | ||
493 | line6_unlink_audio_urbs(line6pcm, &line6pcm->out); | ||
494 | line6_unlink_audio_urbs(line6pcm, &line6pcm->in); | ||
495 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->out); | ||
496 | line6_wait_clear_audio_urbs(line6pcm, &line6pcm->in); | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | Create and register the PCM device and mixer entries. | ||
501 | Create URBs for playback and capture. | ||
502 | */ | ||
503 | int line6_init_pcm(struct usb_line6 *line6, | ||
504 | struct line6_pcm_properties *properties) | ||
505 | { | ||
506 | int i, err; | ||
507 | unsigned ep_read = line6->properties->ep_audio_r; | ||
508 | unsigned ep_write = line6->properties->ep_audio_w; | ||
509 | struct snd_pcm *pcm; | ||
510 | struct snd_line6_pcm *line6pcm; | ||
511 | |||
512 | if (!(line6->properties->capabilities & LINE6_CAP_PCM)) | ||
513 | return 0; /* skip PCM initialization and report success */ | ||
514 | |||
515 | err = snd_line6_new_pcm(line6, &pcm); | ||
516 | if (err < 0) | ||
517 | return err; | ||
518 | |||
519 | line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL); | ||
520 | if (!line6pcm) | ||
521 | return -ENOMEM; | ||
522 | |||
523 | mutex_init(&line6pcm->state_mutex); | ||
524 | line6pcm->pcm = pcm; | ||
525 | line6pcm->properties = properties; | ||
526 | line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255; | ||
527 | line6pcm->volume_monitor = 255; | ||
528 | line6pcm->line6 = line6; | ||
529 | |||
530 | /* Read and write buffers are sized identically, so choose minimum */ | ||
531 | line6pcm->max_packet_size = min( | ||
532 | usb_maxpacket(line6->usbdev, | ||
533 | usb_rcvisocpipe(line6->usbdev, ep_read), 0), | ||
534 | usb_maxpacket(line6->usbdev, | ||
535 | usb_sndisocpipe(line6->usbdev, ep_write), 1)); | ||
536 | |||
537 | spin_lock_init(&line6pcm->out.lock); | ||
538 | spin_lock_init(&line6pcm->in.lock); | ||
539 | line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD; | ||
540 | |||
541 | line6->line6pcm = line6pcm; | ||
542 | |||
543 | pcm->private_data = line6pcm; | ||
544 | pcm->private_free = line6_cleanup_pcm; | ||
545 | |||
546 | err = line6_create_audio_out_urbs(line6pcm); | ||
547 | if (err < 0) | ||
548 | return err; | ||
549 | |||
550 | err = line6_create_audio_in_urbs(line6pcm); | ||
551 | if (err < 0) | ||
552 | return err; | ||
553 | |||
554 | /* mixer: */ | ||
555 | for (i = 0; i < ARRAY_SIZE(line6_controls); i++) { | ||
556 | err = snd_ctl_add(line6->card, | ||
557 | snd_ctl_new1(&line6_controls[i], line6pcm)); | ||
558 | if (err < 0) | ||
559 | return err; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | EXPORT_SYMBOL_GPL(line6_init_pcm); | ||
565 | |||
566 | /* prepare pcm callback */ | ||
567 | int snd_line6_prepare(struct snd_pcm_substream *substream) | ||
568 | { | ||
569 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
570 | struct line6_pcm_stream *pstr = get_stream(line6pcm, substream->stream); | ||
571 | |||
572 | mutex_lock(&line6pcm->state_mutex); | ||
573 | if (!pstr->running) | ||
574 | line6_wait_clear_audio_urbs(line6pcm, pstr); | ||
575 | |||
576 | if (!test_and_set_bit(LINE6_FLAG_PREPARED, &line6pcm->flags)) { | ||
577 | line6pcm->out.count = 0; | ||
578 | line6pcm->out.pos = 0; | ||
579 | line6pcm->out.pos_done = 0; | ||
580 | line6pcm->out.bytes = 0; | ||
581 | line6pcm->in.count = 0; | ||
582 | line6pcm->in.pos_done = 0; | ||
583 | line6pcm->in.bytes = 0; | ||
584 | } | ||
585 | |||
586 | mutex_unlock(&line6pcm->state_mutex); | ||
587 | return 0; | ||
588 | } | ||
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h new file mode 100644 index 000000000000..508410adbd51 --- /dev/null +++ b/sound/usb/line6/pcm.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 | |||
23 | /* number of URBs */ | ||
24 | #define LINE6_ISO_BUFFERS 2 | ||
25 | |||
26 | /* | ||
27 | number of USB frames per URB | ||
28 | The Line 6 Windows driver always transmits two frames per packet, but | ||
29 | the Linux driver performs significantly better (i.e., lower latency) | ||
30 | with only one frame per packet. | ||
31 | */ | ||
32 | #define LINE6_ISO_PACKETS 1 | ||
33 | |||
34 | /* in a "full speed" device (such as the PODxt Pro) this means 1ms */ | ||
35 | #define LINE6_ISO_INTERVAL 1 | ||
36 | |||
37 | #define LINE6_IMPULSE_DEFAULT_PERIOD 100 | ||
38 | |||
39 | /* | ||
40 | Get substream from Line 6 PCM data structure | ||
41 | */ | ||
42 | #define get_substream(line6pcm, stream) \ | ||
43 | (line6pcm->pcm->streams[stream].substream) | ||
44 | |||
45 | /* | ||
46 | PCM mode bits. | ||
47 | |||
48 | There are several features of the Line 6 USB driver which require PCM | ||
49 | data to be exchanged with the device: | ||
50 | *) PCM playback and capture via ALSA | ||
51 | *) software monitoring (for devices without hardware monitoring) | ||
52 | *) optional impulse response measurement | ||
53 | However, from the device's point of view, there is just a single | ||
54 | capture and playback stream, which must be shared between these | ||
55 | subsystems. It is therefore necessary to maintain the state of the | ||
56 | subsystems with respect to PCM usage. | ||
57 | |||
58 | We define two bit flags, "opened" and "running", for each playback | ||
59 | or capture stream. Both can contain the bit flag corresponding to | ||
60 | LINE6_STREAM_* type, | ||
61 | LINE6_STREAM_PCM = ALSA PCM playback or capture | ||
62 | LINE6_STREAM_MONITOR = software monitoring | ||
63 | IMPULSE = optional impulse response measurement | ||
64 | The opened flag indicates whether the buffer is allocated while | ||
65 | the running flag indicates whether the stream is running. | ||
66 | |||
67 | For monitor or impulse operations, the driver needs to call | ||
68 | line6_pcm_acquire() or line6_pcm_release() with the appropriate | ||
69 | LINE6_STREAM_* flag. | ||
70 | */ | ||
71 | |||
72 | /* stream types */ | ||
73 | enum { | ||
74 | LINE6_STREAM_PCM, | ||
75 | LINE6_STREAM_MONITOR, | ||
76 | LINE6_STREAM_IMPULSE, | ||
77 | }; | ||
78 | |||
79 | /* misc bit flags for PCM operation */ | ||
80 | enum { | ||
81 | LINE6_FLAG_PAUSE_PLAYBACK, | ||
82 | LINE6_FLAG_PREPARED, | ||
83 | }; | ||
84 | |||
85 | struct line6_pcm_properties { | ||
86 | struct snd_pcm_hardware playback_hw, capture_hw; | ||
87 | struct snd_pcm_hw_constraint_ratdens rates; | ||
88 | int bytes_per_frame; | ||
89 | }; | ||
90 | |||
91 | struct line6_pcm_stream { | ||
92 | /* allocated URBs */ | ||
93 | struct urb *urbs[LINE6_ISO_BUFFERS]; | ||
94 | |||
95 | /* Temporary buffer; | ||
96 | * Since the packet size is not known in advance, this buffer is | ||
97 | * large enough to store maximum size packets. | ||
98 | */ | ||
99 | unsigned char *buffer; | ||
100 | |||
101 | /* Free frame position in the buffer. */ | ||
102 | snd_pcm_uframes_t pos; | ||
103 | |||
104 | /* Count processed bytes; | ||
105 | * This is modulo period size (to determine when a period is finished). | ||
106 | */ | ||
107 | unsigned bytes; | ||
108 | |||
109 | /* Counter to create desired sample rate */ | ||
110 | unsigned count; | ||
111 | |||
112 | /* period size in bytes */ | ||
113 | unsigned period; | ||
114 | |||
115 | /* Processed frame position in the buffer; | ||
116 | * The contents of the ring buffer have been consumed by the USB | ||
117 | * subsystem (i.e., sent to the USB device) up to this position. | ||
118 | */ | ||
119 | snd_pcm_uframes_t pos_done; | ||
120 | |||
121 | /* Bit mask of active URBs */ | ||
122 | unsigned long active_urbs; | ||
123 | |||
124 | /* Bit mask of URBs currently being unlinked */ | ||
125 | unsigned long unlink_urbs; | ||
126 | |||
127 | /* Spin lock to protect updates of the buffer positions (not contents) | ||
128 | */ | ||
129 | spinlock_t lock; | ||
130 | |||
131 | /* Bit flags for operational stream types */ | ||
132 | unsigned long opened; | ||
133 | |||
134 | /* Bit flags for running stream types */ | ||
135 | unsigned long running; | ||
136 | |||
137 | int last_frame; | ||
138 | }; | ||
139 | |||
140 | struct snd_line6_pcm { | ||
141 | /* Pointer back to the Line 6 driver data structure */ | ||
142 | struct usb_line6 *line6; | ||
143 | |||
144 | /* Properties. */ | ||
145 | struct line6_pcm_properties *properties; | ||
146 | |||
147 | /* ALSA pcm stream */ | ||
148 | struct snd_pcm *pcm; | ||
149 | |||
150 | /* protection to state changes of in/out streams */ | ||
151 | struct mutex state_mutex; | ||
152 | |||
153 | /* Capture and playback streams */ | ||
154 | struct line6_pcm_stream in; | ||
155 | struct line6_pcm_stream out; | ||
156 | |||
157 | /* Previously captured frame (for software monitoring) */ | ||
158 | unsigned char *prev_fbuf; | ||
159 | |||
160 | /* Size of previously captured frame (for software monitoring) */ | ||
161 | int prev_fsize; | ||
162 | |||
163 | /* Maximum size of USB packet */ | ||
164 | int max_packet_size; | ||
165 | |||
166 | /* PCM playback volume (left and right) */ | ||
167 | int volume_playback[2]; | ||
168 | |||
169 | /* PCM monitor volume */ | ||
170 | int volume_monitor; | ||
171 | |||
172 | /* Volume of impulse response test signal (if zero, test is disabled) */ | ||
173 | int impulse_volume; | ||
174 | |||
175 | /* Period of impulse response test signal */ | ||
176 | int impulse_period; | ||
177 | |||
178 | /* Counter for impulse response test signal */ | ||
179 | int impulse_count; | ||
180 | |||
181 | /* Several status bits (see LINE6_FLAG_*) */ | ||
182 | unsigned long flags; | ||
183 | }; | ||
184 | |||
185 | extern int line6_init_pcm(struct usb_line6 *line6, | ||
186 | struct line6_pcm_properties *properties); | ||
187 | extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd); | ||
188 | extern int snd_line6_prepare(struct snd_pcm_substream *substream); | ||
189 | extern int snd_line6_hw_params(struct snd_pcm_substream *substream, | ||
190 | struct snd_pcm_hw_params *hw_params); | ||
191 | extern int snd_line6_hw_free(struct snd_pcm_substream *substream); | ||
192 | extern snd_pcm_uframes_t snd_line6_pointer(struct snd_pcm_substream *substream); | ||
193 | extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); | ||
194 | extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int type); | ||
195 | extern void line6_pcm_release(struct snd_line6_pcm *line6pcm, int type); | ||
196 | |||
197 | #endif | ||
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c new file mode 100644 index 000000000000..05dee690f487 --- /dev/null +++ b/sound/usb/line6/playback.c | |||
@@ -0,0 +1,429 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 "capture.h" | ||
18 | #include "driver.h" | ||
19 | #include "pcm.h" | ||
20 | #include "playback.h" | ||
21 | |||
22 | /* | ||
23 | Software stereo volume control. | ||
24 | */ | ||
25 | static void change_volume(struct urb *urb_out, int volume[], | ||
26 | int bytes_per_frame) | ||
27 | { | ||
28 | int chn = 0; | ||
29 | |||
30 | if (volume[0] == 256 && volume[1] == 256) | ||
31 | return; /* maximum volume - no change */ | ||
32 | |||
33 | if (bytes_per_frame == 4) { | ||
34 | __le16 *p, *buf_end; | ||
35 | |||
36 | p = (__le16 *)urb_out->transfer_buffer; | ||
37 | buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); | ||
38 | |||
39 | for (; p < buf_end; ++p) { | ||
40 | short pv = le16_to_cpu(*p); | ||
41 | int val = (pv * volume[chn & 1]) >> 8; | ||
42 | pv = clamp(val, 0x7fff, -0x8000); | ||
43 | *p = cpu_to_le16(pv); | ||
44 | ++chn; | ||
45 | } | ||
46 | } else if (bytes_per_frame == 6) { | ||
47 | unsigned char *p, *buf_end; | ||
48 | |||
49 | p = (unsigned char *)urb_out->transfer_buffer; | ||
50 | buf_end = p + urb_out->transfer_buffer_length; | ||
51 | |||
52 | for (; p < buf_end; p += 3) { | ||
53 | int val; | ||
54 | |||
55 | val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); | ||
56 | val = (val * volume[chn & 1]) >> 8; | ||
57 | val = clamp(val, 0x7fffff, -0x800000); | ||
58 | p[0] = val; | ||
59 | p[1] = val >> 8; | ||
60 | p[2] = val >> 16; | ||
61 | ++chn; | ||
62 | } | ||
63 | } | ||
64 | } | ||
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 | /* | ||
110 | Add signal to buffer for software monitoring. | ||
111 | */ | ||
112 | static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, | ||
113 | int volume, int bytes_per_frame) | ||
114 | { | ||
115 | if (volume == 0) | ||
116 | return; /* zero volume - no change */ | ||
117 | |||
118 | if (bytes_per_frame == 4) { | ||
119 | __le16 *pi, *po, *buf_end; | ||
120 | |||
121 | pi = (__le16 *)signal; | ||
122 | po = (__le16 *)urb_out->transfer_buffer; | ||
123 | buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); | ||
124 | |||
125 | for (; po < buf_end; ++pi, ++po) { | ||
126 | short pov = le16_to_cpu(*po); | ||
127 | short piv = le16_to_cpu(*pi); | ||
128 | int val = pov + ((piv * volume) >> 8); | ||
129 | pov = clamp(val, 0x7fff, -0x8000); | ||
130 | *po = cpu_to_le16(pov); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | We don't need to handle devices with 6 bytes per frame here | ||
136 | since they all support hardware monitoring. | ||
137 | */ | ||
138 | } | ||
139 | |||
140 | /* | ||
141 | Find a free URB, prepare audio data, and submit URB. | ||
142 | must be called in line6pcm->out.lock context | ||
143 | */ | ||
144 | static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | ||
145 | { | ||
146 | int index; | ||
147 | int i, urb_size, urb_frames; | ||
148 | int ret; | ||
149 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; | ||
150 | const int frame_increment = | ||
151 | line6pcm->properties->rates.rats[0].num_min; | ||
152 | const int frame_factor = | ||
153 | line6pcm->properties->rates.rats[0].den * | ||
154 | (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); | ||
155 | struct urb *urb_out; | ||
156 | |||
157 | index = | ||
158 | find_first_zero_bit(&line6pcm->out.active_urbs, LINE6_ISO_BUFFERS); | ||
159 | |||
160 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { | ||
161 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); | ||
162 | return -EINVAL; | ||
163 | } | ||
164 | |||
165 | urb_out = line6pcm->out.urbs[index]; | ||
166 | urb_size = 0; | ||
167 | |||
168 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | ||
169 | /* compute frame size for given sampling rate */ | ||
170 | int fsize = 0; | ||
171 | struct usb_iso_packet_descriptor *fout = | ||
172 | &urb_out->iso_frame_desc[i]; | ||
173 | |||
174 | fsize = line6pcm->prev_fsize; | ||
175 | if (fsize == 0) { | ||
176 | int n; | ||
177 | |||
178 | line6pcm->out.count += frame_increment; | ||
179 | n = line6pcm->out.count / frame_factor; | ||
180 | line6pcm->out.count -= n * frame_factor; | ||
181 | fsize = n * bytes_per_frame; | ||
182 | } | ||
183 | |||
184 | fout->offset = urb_size; | ||
185 | fout->length = fsize; | ||
186 | urb_size += fsize; | ||
187 | } | ||
188 | |||
189 | if (urb_size == 0) { | ||
190 | /* can't determine URB size */ | ||
191 | dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | urb_frames = urb_size / bytes_per_frame; | ||
196 | urb_out->transfer_buffer = | ||
197 | line6pcm->out.buffer + | ||
198 | index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; | ||
199 | urb_out->transfer_buffer_length = urb_size; | ||
200 | urb_out->context = line6pcm; | ||
201 | |||
202 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running) && | ||
203 | !test_bit(LINE6_FLAG_PAUSE_PLAYBACK, &line6pcm->flags)) { | ||
204 | struct snd_pcm_runtime *runtime = | ||
205 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; | ||
206 | |||
207 | if (line6pcm->out.pos + urb_frames > runtime->buffer_size) { | ||
208 | /* | ||
209 | The transferred area goes over buffer boundary, | ||
210 | copy the data to the temp buffer. | ||
211 | */ | ||
212 | int len; | ||
213 | |||
214 | len = runtime->buffer_size - line6pcm->out.pos; | ||
215 | |||
216 | if (len > 0) { | ||
217 | memcpy(urb_out->transfer_buffer, | ||
218 | runtime->dma_area + | ||
219 | line6pcm->out.pos * bytes_per_frame, | ||
220 | len * bytes_per_frame); | ||
221 | memcpy(urb_out->transfer_buffer + | ||
222 | len * bytes_per_frame, runtime->dma_area, | ||
223 | (urb_frames - len) * bytes_per_frame); | ||
224 | } else | ||
225 | dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", | ||
226 | len); | ||
227 | } else { | ||
228 | memcpy(urb_out->transfer_buffer, | ||
229 | runtime->dma_area + | ||
230 | line6pcm->out.pos * bytes_per_frame, | ||
231 | urb_out->transfer_buffer_length); | ||
232 | } | ||
233 | |||
234 | line6pcm->out.pos += urb_frames; | ||
235 | if (line6pcm->out.pos >= runtime->buffer_size) | ||
236 | line6pcm->out.pos -= runtime->buffer_size; | ||
237 | |||
238 | change_volume(urb_out, line6pcm->volume_playback, | ||
239 | bytes_per_frame); | ||
240 | } else { | ||
241 | memset(urb_out->transfer_buffer, 0, | ||
242 | urb_out->transfer_buffer_length); | ||
243 | } | ||
244 | |||
245 | spin_lock_nested(&line6pcm->in.lock, SINGLE_DEPTH_NESTING); | ||
246 | if (line6pcm->prev_fbuf) { | ||
247 | if (test_bit(LINE6_STREAM_IMPULSE, &line6pcm->out.running)) { | ||
248 | create_impulse_test_signal(line6pcm, urb_out, | ||
249 | bytes_per_frame); | ||
250 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->in.running)) { | ||
251 | line6_capture_copy(line6pcm, | ||
252 | urb_out->transfer_buffer, | ||
253 | urb_out-> | ||
254 | transfer_buffer_length); | ||
255 | line6_capture_check_period(line6pcm, | ||
256 | urb_out->transfer_buffer_length); | ||
257 | } | ||
258 | } else { | ||
259 | if (!(line6pcm->line6->properties->capabilities & LINE6_CAP_HWMON) | ||
260 | && line6pcm->out.running && line6pcm->in.running) | ||
261 | add_monitor_signal(urb_out, line6pcm->prev_fbuf, | ||
262 | line6pcm->volume_monitor, | ||
263 | bytes_per_frame); | ||
264 | } | ||
265 | line6pcm->prev_fbuf = NULL; | ||
266 | line6pcm->prev_fsize = 0; | ||
267 | } | ||
268 | spin_unlock(&line6pcm->in.lock); | ||
269 | |||
270 | ret = usb_submit_urb(urb_out, GFP_ATOMIC); | ||
271 | |||
272 | if (ret == 0) | ||
273 | set_bit(index, &line6pcm->out.active_urbs); | ||
274 | else | ||
275 | dev_err(line6pcm->line6->ifcdev, | ||
276 | "URB out #%d submission failed (%d)\n", index, ret); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | Submit all currently available playback URBs. | ||
283 | must be called in line6pcm->out.lock context | ||
284 | */ | ||
285 | int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) | ||
286 | { | ||
287 | int ret = 0, i; | ||
288 | |||
289 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
290 | ret = submit_audio_out_urb(line6pcm); | ||
291 | if (ret < 0) | ||
292 | break; | ||
293 | } | ||
294 | |||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | Callback for completed playback URB. | ||
300 | */ | ||
301 | static void audio_out_callback(struct urb *urb) | ||
302 | { | ||
303 | int i, index, length = 0, shutdown = 0; | ||
304 | unsigned long flags; | ||
305 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; | ||
306 | struct snd_pcm_substream *substream = | ||
307 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
308 | |||
309 | #if USE_CLEAR_BUFFER_WORKAROUND | ||
310 | memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); | ||
311 | #endif | ||
312 | |||
313 | line6pcm->out.last_frame = urb->start_frame; | ||
314 | |||
315 | /* find index of URB */ | ||
316 | for (index = 0; index < LINE6_ISO_BUFFERS; index++) | ||
317 | if (urb == line6pcm->out.urbs[index]) | ||
318 | break; | ||
319 | |||
320 | if (index >= LINE6_ISO_BUFFERS) | ||
321 | return; /* URB has been unlinked asynchronously */ | ||
322 | |||
323 | for (i = 0; i < LINE6_ISO_PACKETS; i++) | ||
324 | length += urb->iso_frame_desc[i].length; | ||
325 | |||
326 | spin_lock_irqsave(&line6pcm->out.lock, flags); | ||
327 | |||
328 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { | ||
329 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
330 | |||
331 | line6pcm->out.pos_done += | ||
332 | length / line6pcm->properties->bytes_per_frame; | ||
333 | |||
334 | if (line6pcm->out.pos_done >= runtime->buffer_size) | ||
335 | line6pcm->out.pos_done -= runtime->buffer_size; | ||
336 | } | ||
337 | |||
338 | clear_bit(index, &line6pcm->out.active_urbs); | ||
339 | |||
340 | for (i = 0; i < LINE6_ISO_PACKETS; i++) | ||
341 | if (urb->iso_frame_desc[i].status == -EXDEV) { | ||
342 | shutdown = 1; | ||
343 | break; | ||
344 | } | ||
345 | |||
346 | if (test_and_clear_bit(index, &line6pcm->out.unlink_urbs)) | ||
347 | shutdown = 1; | ||
348 | |||
349 | if (!shutdown) { | ||
350 | submit_audio_out_urb(line6pcm); | ||
351 | |||
352 | if (test_bit(LINE6_STREAM_PCM, &line6pcm->out.running)) { | ||
353 | line6pcm->out.bytes += length; | ||
354 | if (line6pcm->out.bytes >= line6pcm->out.period) { | ||
355 | line6pcm->out.bytes %= line6pcm->out.period; | ||
356 | spin_unlock(&line6pcm->out.lock); | ||
357 | snd_pcm_period_elapsed(substream); | ||
358 | spin_lock(&line6pcm->out.lock); | ||
359 | } | ||
360 | } | ||
361 | } | ||
362 | spin_unlock_irqrestore(&line6pcm->out.lock, flags); | ||
363 | } | ||
364 | |||
365 | /* open playback callback */ | ||
366 | static int snd_line6_playback_open(struct snd_pcm_substream *substream) | ||
367 | { | ||
368 | int err; | ||
369 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
370 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | ||
371 | |||
372 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
373 | &line6pcm->properties->rates); | ||
374 | if (err < 0) | ||
375 | return err; | ||
376 | |||
377 | runtime->hw = line6pcm->properties->playback_hw; | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | /* close playback callback */ | ||
382 | static int snd_line6_playback_close(struct snd_pcm_substream *substream) | ||
383 | { | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* playback operators */ | ||
388 | struct snd_pcm_ops snd_line6_playback_ops = { | ||
389 | .open = snd_line6_playback_open, | ||
390 | .close = snd_line6_playback_close, | ||
391 | .ioctl = snd_pcm_lib_ioctl, | ||
392 | .hw_params = snd_line6_hw_params, | ||
393 | .hw_free = snd_line6_hw_free, | ||
394 | .prepare = snd_line6_prepare, | ||
395 | .trigger = snd_line6_trigger, | ||
396 | .pointer = snd_line6_pointer, | ||
397 | }; | ||
398 | |||
399 | int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) | ||
400 | { | ||
401 | struct usb_line6 *line6 = line6pcm->line6; | ||
402 | int i; | ||
403 | |||
404 | /* create audio URBs and fill in constant values: */ | ||
405 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | ||
406 | struct urb *urb; | ||
407 | |||
408 | /* URB for audio out: */ | ||
409 | urb = line6pcm->out.urbs[i] = | ||
410 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); | ||
411 | |||
412 | if (urb == NULL) | ||
413 | return -ENOMEM; | ||
414 | |||
415 | urb->dev = line6->usbdev; | ||
416 | urb->pipe = | ||
417 | usb_sndisocpipe(line6->usbdev, | ||
418 | line6->properties->ep_audio_w & | ||
419 | USB_ENDPOINT_NUMBER_MASK); | ||
420 | urb->transfer_flags = URB_ISO_ASAP; | ||
421 | urb->start_frame = -1; | ||
422 | urb->number_of_packets = LINE6_ISO_PACKETS; | ||
423 | urb->interval = LINE6_ISO_INTERVAL; | ||
424 | urb->error_count = 0; | ||
425 | urb->complete = audio_out_callback; | ||
426 | } | ||
427 | |||
428 | return 0; | ||
429 | } | ||
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h new file mode 100644 index 000000000000..51fce29e8726 --- /dev/null +++ b/sound/usb/line6/playback.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm); | ||
34 | |||
35 | #endif | ||
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c new file mode 100644 index 000000000000..daf81d169a42 --- /dev/null +++ b/sound/usb/line6/pod.c | |||
@@ -0,0 +1,584 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 <linux/interrupt.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/usb.h> | ||
17 | |||
18 | #include <sound/core.h> | ||
19 | #include <sound/control.h> | ||
20 | |||
21 | #include "capture.h" | ||
22 | #include "driver.h" | ||
23 | #include "playback.h" | ||
24 | |||
25 | /* | ||
26 | Locate name in binary program dump | ||
27 | */ | ||
28 | #define POD_NAME_OFFSET 0 | ||
29 | #define POD_NAME_LENGTH 16 | ||
30 | |||
31 | /* | ||
32 | Other constants | ||
33 | */ | ||
34 | #define POD_CONTROL_SIZE 0x80 | ||
35 | #define POD_BUFSIZE_DUMPREQ 7 | ||
36 | #define POD_STARTUP_DELAY 1000 | ||
37 | |||
38 | /* | ||
39 | Stages of POD startup procedure | ||
40 | */ | ||
41 | enum { | ||
42 | POD_STARTUP_INIT = 1, | ||
43 | POD_STARTUP_VERSIONREQ, | ||
44 | POD_STARTUP_WORKQUEUE, | ||
45 | POD_STARTUP_SETUP, | ||
46 | POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 | ||
47 | }; | ||
48 | |||
49 | enum { | ||
50 | LINE6_BASSPODXT, | ||
51 | LINE6_BASSPODXTLIVE, | ||
52 | LINE6_BASSPODXTPRO, | ||
53 | LINE6_POCKETPOD, | ||
54 | LINE6_PODXT, | ||
55 | LINE6_PODXTLIVE_POD, | ||
56 | LINE6_PODXTPRO, | ||
57 | }; | ||
58 | |||
59 | struct usb_line6_pod { | ||
60 | /* Generic Line 6 USB data */ | ||
61 | struct usb_line6 line6; | ||
62 | |||
63 | /* Instrument monitor level */ | ||
64 | int monitor_level; | ||
65 | |||
66 | /* Timer for device initialization */ | ||
67 | struct timer_list startup_timer; | ||
68 | |||
69 | /* Work handler for device initialization */ | ||
70 | struct work_struct startup_work; | ||
71 | |||
72 | /* Current progress in startup procedure */ | ||
73 | int startup_progress; | ||
74 | |||
75 | /* Serial number of device */ | ||
76 | u32 serial_number; | ||
77 | |||
78 | /* Firmware version (x 100) */ | ||
79 | int firmware_version; | ||
80 | |||
81 | /* Device ID */ | ||
82 | int device_id; | ||
83 | }; | ||
84 | |||
85 | #define POD_SYSEX_CODE 3 | ||
86 | #define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ | ||
87 | |||
88 | /* *INDENT-OFF* */ | ||
89 | |||
90 | enum { | ||
91 | POD_SYSEX_SAVE = 0x24, | ||
92 | POD_SYSEX_SYSTEM = 0x56, | ||
93 | POD_SYSEX_SYSTEMREQ = 0x57, | ||
94 | /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ | ||
95 | POD_SYSEX_STORE = 0x71, | ||
96 | POD_SYSEX_FINISH = 0x72, | ||
97 | POD_SYSEX_DUMPMEM = 0x73, | ||
98 | POD_SYSEX_DUMP = 0x74, | ||
99 | POD_SYSEX_DUMPREQ = 0x75 | ||
100 | |||
101 | /* dumps entire internal memory of PODxt Pro */ | ||
102 | /* POD_SYSEX_DUMPMEM2 = 0x76 */ | ||
103 | }; | ||
104 | |||
105 | enum { | ||
106 | POD_MONITOR_LEVEL = 0x04, | ||
107 | POD_SYSTEM_INVALID = 0x10000 | ||
108 | }; | ||
109 | |||
110 | /* *INDENT-ON* */ | ||
111 | |||
112 | enum { | ||
113 | POD_DUMP_MEMORY = 2 | ||
114 | }; | ||
115 | |||
116 | enum { | ||
117 | POD_BUSY_READ, | ||
118 | POD_BUSY_WRITE, | ||
119 | POD_CHANNEL_DIRTY, | ||
120 | POD_SAVE_PRESSED, | ||
121 | POD_BUSY_MIDISEND | ||
122 | }; | ||
123 | |||
124 | static struct snd_ratden pod_ratden = { | ||
125 | .num_min = 78125, | ||
126 | .num_max = 78125, | ||
127 | .num_step = 1, | ||
128 | .den = 2 | ||
129 | }; | ||
130 | |||
131 | static struct line6_pcm_properties pod_pcm_properties = { | ||
132 | .playback_hw = { | ||
133 | .info = (SNDRV_PCM_INFO_MMAP | | ||
134 | SNDRV_PCM_INFO_INTERLEAVED | | ||
135 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
136 | SNDRV_PCM_INFO_MMAP_VALID | | ||
137 | SNDRV_PCM_INFO_PAUSE | | ||
138 | SNDRV_PCM_INFO_SYNC_START), | ||
139 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
140 | .rates = SNDRV_PCM_RATE_KNOT, | ||
141 | .rate_min = 39062, | ||
142 | .rate_max = 39063, | ||
143 | .channels_min = 2, | ||
144 | .channels_max = 2, | ||
145 | .buffer_bytes_max = 60000, | ||
146 | .period_bytes_min = 64, | ||
147 | .period_bytes_max = 8192, | ||
148 | .periods_min = 1, | ||
149 | .periods_max = 1024}, | ||
150 | .capture_hw = { | ||
151 | .info = (SNDRV_PCM_INFO_MMAP | | ||
152 | SNDRV_PCM_INFO_INTERLEAVED | | ||
153 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
154 | SNDRV_PCM_INFO_MMAP_VALID | | ||
155 | SNDRV_PCM_INFO_SYNC_START), | ||
156 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
157 | .rates = SNDRV_PCM_RATE_KNOT, | ||
158 | .rate_min = 39062, | ||
159 | .rate_max = 39063, | ||
160 | .channels_min = 2, | ||
161 | .channels_max = 2, | ||
162 | .buffer_bytes_max = 60000, | ||
163 | .period_bytes_min = 64, | ||
164 | .period_bytes_max = 8192, | ||
165 | .periods_min = 1, | ||
166 | .periods_max = 1024}, | ||
167 | .rates = { | ||
168 | .nrats = 1, | ||
169 | .rats = &pod_ratden}, | ||
170 | .bytes_per_frame = POD_BYTES_PER_FRAME | ||
171 | }; | ||
172 | |||
173 | static const char pod_version_header[] = { | ||
174 | 0xf2, 0x7e, 0x7f, 0x06, 0x02 | ||
175 | }; | ||
176 | |||
177 | /* forward declarations: */ | ||
178 | static void pod_startup2(unsigned long data); | ||
179 | static void pod_startup3(struct usb_line6_pod *pod); | ||
180 | |||
181 | static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, | ||
182 | int size) | ||
183 | { | ||
184 | return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, | ||
185 | size); | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | Process a completely received message. | ||
190 | */ | ||
191 | static void line6_pod_process_message(struct usb_line6 *line6) | ||
192 | { | ||
193 | struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; | ||
194 | const unsigned char *buf = pod->line6.buffer_message; | ||
195 | |||
196 | if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { | ||
197 | pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; | ||
198 | pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | | ||
199 | (int) buf[10]; | ||
200 | pod_startup3(pod); | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | /* Only look for sysex messages from this device */ | ||
205 | if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && | ||
206 | buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { | ||
207 | return; | ||
208 | } | ||
209 | if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) | ||
210 | return; | ||
211 | |||
212 | if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) { | ||
213 | short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | | ||
214 | ((int)buf[9] << 4) | (int)buf[10]; | ||
215 | pod->monitor_level = value; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | Send system parameter (from integer). | ||
221 | */ | ||
222 | static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, | ||
223 | int code) | ||
224 | { | ||
225 | char *sysex; | ||
226 | static const int size = 5; | ||
227 | |||
228 | sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); | ||
229 | if (!sysex) | ||
230 | return -ENOMEM; | ||
231 | sysex[SYSEX_DATA_OFS] = code; | ||
232 | sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; | ||
233 | sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; | ||
234 | sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; | ||
235 | sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; | ||
236 | line6_send_sysex_message(&pod->line6, sysex, size); | ||
237 | kfree(sysex); | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | "read" request on "serial_number" special file. | ||
243 | */ | ||
244 | static ssize_t serial_number_show(struct device *dev, | ||
245 | struct device_attribute *attr, char *buf) | ||
246 | { | ||
247 | struct usb_interface *interface = to_usb_interface(dev); | ||
248 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
249 | |||
250 | return sprintf(buf, "%u\n", pod->serial_number); | ||
251 | } | ||
252 | |||
253 | /* | ||
254 | "read" request on "firmware_version" special file. | ||
255 | */ | ||
256 | static ssize_t firmware_version_show(struct device *dev, | ||
257 | struct device_attribute *attr, char *buf) | ||
258 | { | ||
259 | struct usb_interface *interface = to_usb_interface(dev); | ||
260 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
261 | |||
262 | return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, | ||
263 | pod->firmware_version % 100); | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | "read" request on "device_id" special file. | ||
268 | */ | ||
269 | static ssize_t device_id_show(struct device *dev, | ||
270 | struct device_attribute *attr, char *buf) | ||
271 | { | ||
272 | struct usb_interface *interface = to_usb_interface(dev); | ||
273 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | ||
274 | |||
275 | return sprintf(buf, "%d\n", pod->device_id); | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | POD startup procedure. | ||
280 | This is a sequence of functions with special requirements (e.g., must | ||
281 | not run immediately after initialization, must not run in interrupt | ||
282 | context). After the last one has finished, the device is ready to use. | ||
283 | */ | ||
284 | |||
285 | static void pod_startup1(struct usb_line6_pod *pod) | ||
286 | { | ||
287 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); | ||
288 | |||
289 | /* delay startup procedure: */ | ||
290 | line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, | ||
291 | (unsigned long)pod); | ||
292 | } | ||
293 | |||
294 | static void pod_startup2(unsigned long data) | ||
295 | { | ||
296 | struct usb_line6_pod *pod = (struct usb_line6_pod *)data; | ||
297 | struct usb_line6 *line6 = &pod->line6; | ||
298 | |||
299 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); | ||
300 | |||
301 | /* request firmware version: */ | ||
302 | line6_version_request_async(line6); | ||
303 | } | ||
304 | |||
305 | static void pod_startup3(struct usb_line6_pod *pod) | ||
306 | { | ||
307 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); | ||
308 | |||
309 | /* schedule work for global work queue: */ | ||
310 | schedule_work(&pod->startup_work); | ||
311 | } | ||
312 | |||
313 | static void pod_startup4(struct work_struct *work) | ||
314 | { | ||
315 | struct usb_line6_pod *pod = | ||
316 | container_of(work, struct usb_line6_pod, startup_work); | ||
317 | struct usb_line6 *line6 = &pod->line6; | ||
318 | |||
319 | CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); | ||
320 | |||
321 | /* serial number: */ | ||
322 | line6_read_serial_number(&pod->line6, &pod->serial_number); | ||
323 | |||
324 | /* ALSA audio interface: */ | ||
325 | snd_card_register(line6->card); | ||
326 | } | ||
327 | |||
328 | /* POD special files: */ | ||
329 | static DEVICE_ATTR_RO(device_id); | ||
330 | static DEVICE_ATTR_RO(firmware_version); | ||
331 | static DEVICE_ATTR_RO(serial_number); | ||
332 | |||
333 | static struct attribute *pod_dev_attrs[] = { | ||
334 | &dev_attr_device_id.attr, | ||
335 | &dev_attr_firmware_version.attr, | ||
336 | &dev_attr_serial_number.attr, | ||
337 | NULL | ||
338 | }; | ||
339 | |||
340 | static const struct attribute_group pod_dev_attr_group = { | ||
341 | .name = "pod", | ||
342 | .attrs = pod_dev_attrs, | ||
343 | }; | ||
344 | |||
345 | /* control info callback */ | ||
346 | static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, | ||
347 | struct snd_ctl_elem_info *uinfo) | ||
348 | { | ||
349 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
350 | uinfo->count = 1; | ||
351 | uinfo->value.integer.min = 0; | ||
352 | uinfo->value.integer.max = 65535; | ||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /* control get callback */ | ||
357 | static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, | ||
358 | struct snd_ctl_elem_value *ucontrol) | ||
359 | { | ||
360 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
361 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; | ||
362 | |||
363 | ucontrol->value.integer.value[0] = pod->monitor_level; | ||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | /* control put callback */ | ||
368 | static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, | ||
369 | struct snd_ctl_elem_value *ucontrol) | ||
370 | { | ||
371 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
372 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; | ||
373 | |||
374 | if (ucontrol->value.integer.value[0] == pod->monitor_level) | ||
375 | return 0; | ||
376 | |||
377 | pod->monitor_level = ucontrol->value.integer.value[0]; | ||
378 | pod_set_system_param_int(pod, ucontrol->value.integer.value[0], | ||
379 | POD_MONITOR_LEVEL); | ||
380 | return 1; | ||
381 | } | ||
382 | |||
383 | /* control definition */ | ||
384 | static struct snd_kcontrol_new pod_control_monitor = { | ||
385 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
386 | .name = "Monitor Playback Volume", | ||
387 | .index = 0, | ||
388 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
389 | .info = snd_pod_control_monitor_info, | ||
390 | .get = snd_pod_control_monitor_get, | ||
391 | .put = snd_pod_control_monitor_put | ||
392 | }; | ||
393 | |||
394 | /* | ||
395 | POD device disconnected. | ||
396 | */ | ||
397 | static void line6_pod_disconnect(struct usb_line6 *line6) | ||
398 | { | ||
399 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6; | ||
400 | |||
401 | del_timer_sync(&pod->startup_timer); | ||
402 | cancel_work_sync(&pod->startup_work); | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | Try to init POD device. | ||
407 | */ | ||
408 | static int pod_init(struct usb_line6 *line6, | ||
409 | const struct usb_device_id *id) | ||
410 | { | ||
411 | int err; | ||
412 | struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; | ||
413 | |||
414 | line6->process_message = line6_pod_process_message; | ||
415 | line6->disconnect = line6_pod_disconnect; | ||
416 | |||
417 | init_timer(&pod->startup_timer); | ||
418 | INIT_WORK(&pod->startup_work, pod_startup4); | ||
419 | |||
420 | /* create sysfs entries: */ | ||
421 | err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group); | ||
422 | if (err < 0) | ||
423 | return err; | ||
424 | |||
425 | /* initialize MIDI subsystem: */ | ||
426 | err = line6_init_midi(line6); | ||
427 | if (err < 0) | ||
428 | return err; | ||
429 | |||
430 | /* initialize PCM subsystem: */ | ||
431 | err = line6_init_pcm(line6, &pod_pcm_properties); | ||
432 | if (err < 0) | ||
433 | return err; | ||
434 | |||
435 | /* register monitor control: */ | ||
436 | err = snd_ctl_add(line6->card, | ||
437 | snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); | ||
438 | if (err < 0) | ||
439 | return err; | ||
440 | |||
441 | /* | ||
442 | When the sound card is registered at this point, the PODxt Live | ||
443 | displays "Invalid Code Error 07", so we do it later in the event | ||
444 | handler. | ||
445 | */ | ||
446 | |||
447 | if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { | ||
448 | pod->monitor_level = POD_SYSTEM_INVALID; | ||
449 | |||
450 | /* initiate startup procedure: */ | ||
451 | pod_startup1(pod); | ||
452 | } | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) | ||
458 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) | ||
459 | |||
460 | /* table of devices that work with this driver */ | ||
461 | static const struct usb_device_id pod_id_table[] = { | ||
462 | { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, | ||
463 | { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, | ||
464 | { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, | ||
465 | { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, | ||
466 | { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, | ||
467 | { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, | ||
468 | { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, | ||
469 | {} | ||
470 | }; | ||
471 | |||
472 | MODULE_DEVICE_TABLE(usb, pod_id_table); | ||
473 | |||
474 | static const struct line6_properties pod_properties_table[] = { | ||
475 | [LINE6_BASSPODXT] = { | ||
476 | .id = "BassPODxt", | ||
477 | .name = "BassPODxt", | ||
478 | .capabilities = LINE6_CAP_CONTROL | ||
479 | | LINE6_CAP_PCM | ||
480 | | LINE6_CAP_HWMON, | ||
481 | .altsetting = 5, | ||
482 | .ep_ctrl_r = 0x84, | ||
483 | .ep_ctrl_w = 0x03, | ||
484 | .ep_audio_r = 0x82, | ||
485 | .ep_audio_w = 0x01, | ||
486 | }, | ||
487 | [LINE6_BASSPODXTLIVE] = { | ||
488 | .id = "BassPODxtLive", | ||
489 | .name = "BassPODxt Live", | ||
490 | .capabilities = LINE6_CAP_CONTROL | ||
491 | | LINE6_CAP_PCM | ||
492 | | LINE6_CAP_HWMON, | ||
493 | .altsetting = 1, | ||
494 | .ep_ctrl_r = 0x84, | ||
495 | .ep_ctrl_w = 0x03, | ||
496 | .ep_audio_r = 0x82, | ||
497 | .ep_audio_w = 0x01, | ||
498 | }, | ||
499 | [LINE6_BASSPODXTPRO] = { | ||
500 | .id = "BassPODxtPro", | ||
501 | .name = "BassPODxt Pro", | ||
502 | .capabilities = LINE6_CAP_CONTROL | ||
503 | | LINE6_CAP_PCM | ||
504 | | LINE6_CAP_HWMON, | ||
505 | .altsetting = 5, | ||
506 | .ep_ctrl_r = 0x84, | ||
507 | .ep_ctrl_w = 0x03, | ||
508 | .ep_audio_r = 0x82, | ||
509 | .ep_audio_w = 0x01, | ||
510 | }, | ||
511 | [LINE6_POCKETPOD] = { | ||
512 | .id = "PocketPOD", | ||
513 | .name = "Pocket POD", | ||
514 | .capabilities = LINE6_CAP_CONTROL, | ||
515 | .altsetting = 0, | ||
516 | .ep_ctrl_r = 0x82, | ||
517 | .ep_ctrl_w = 0x02, | ||
518 | /* no audio channel */ | ||
519 | }, | ||
520 | [LINE6_PODXT] = { | ||
521 | .id = "PODxt", | ||
522 | .name = "PODxt", | ||
523 | .capabilities = LINE6_CAP_CONTROL | ||
524 | | LINE6_CAP_PCM | ||
525 | | LINE6_CAP_HWMON, | ||
526 | .altsetting = 5, | ||
527 | .ep_ctrl_r = 0x84, | ||
528 | .ep_ctrl_w = 0x03, | ||
529 | .ep_audio_r = 0x82, | ||
530 | .ep_audio_w = 0x01, | ||
531 | }, | ||
532 | [LINE6_PODXTLIVE_POD] = { | ||
533 | .id = "PODxtLive", | ||
534 | .name = "PODxt Live", | ||
535 | .capabilities = LINE6_CAP_CONTROL | ||
536 | | LINE6_CAP_PCM | ||
537 | | LINE6_CAP_HWMON, | ||
538 | .altsetting = 1, | ||
539 | .ep_ctrl_r = 0x84, | ||
540 | .ep_ctrl_w = 0x03, | ||
541 | .ep_audio_r = 0x82, | ||
542 | .ep_audio_w = 0x01, | ||
543 | }, | ||
544 | [LINE6_PODXTPRO] = { | ||
545 | .id = "PODxtPro", | ||
546 | .name = "PODxt Pro", | ||
547 | .capabilities = LINE6_CAP_CONTROL | ||
548 | | LINE6_CAP_PCM | ||
549 | | LINE6_CAP_HWMON, | ||
550 | .altsetting = 5, | ||
551 | .ep_ctrl_r = 0x84, | ||
552 | .ep_ctrl_w = 0x03, | ||
553 | .ep_audio_r = 0x82, | ||
554 | .ep_audio_w = 0x01, | ||
555 | }, | ||
556 | }; | ||
557 | |||
558 | /* | ||
559 | Probe USB device. | ||
560 | */ | ||
561 | static int pod_probe(struct usb_interface *interface, | ||
562 | const struct usb_device_id *id) | ||
563 | { | ||
564 | return line6_probe(interface, id, "Line6-POD", | ||
565 | &pod_properties_table[id->driver_info], | ||
566 | pod_init, sizeof(struct usb_line6_pod)); | ||
567 | } | ||
568 | |||
569 | static struct usb_driver pod_driver = { | ||
570 | .name = KBUILD_MODNAME, | ||
571 | .probe = pod_probe, | ||
572 | .disconnect = line6_disconnect, | ||
573 | #ifdef CONFIG_PM | ||
574 | .suspend = line6_suspend, | ||
575 | .resume = line6_resume, | ||
576 | .reset_resume = line6_resume, | ||
577 | #endif | ||
578 | .id_table = pod_id_table, | ||
579 | }; | ||
580 | |||
581 | module_usb_driver(pod_driver); | ||
582 | |||
583 | MODULE_DESCRIPTION("Line 6 POD USB driver"); | ||
584 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c new file mode 100644 index 000000000000..63dcaef41ac3 --- /dev/null +++ b/sound/usb/line6/podhd.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Line 6 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 <linux/usb.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/pcm.h> | ||
17 | |||
18 | #include "driver.h" | ||
19 | #include "pcm.h" | ||
20 | |||
21 | enum { | ||
22 | LINE6_PODHD300, | ||
23 | LINE6_PODHD400, | ||
24 | LINE6_PODHD500_0, | ||
25 | LINE6_PODHD500_1, | ||
26 | }; | ||
27 | |||
28 | #define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ | ||
29 | |||
30 | static struct snd_ratden podhd_ratden = { | ||
31 | .num_min = 48000, | ||
32 | .num_max = 48000, | ||
33 | .num_step = 1, | ||
34 | .den = 1, | ||
35 | }; | ||
36 | |||
37 | static struct line6_pcm_properties podhd_pcm_properties = { | ||
38 | .playback_hw = { | ||
39 | .info = (SNDRV_PCM_INFO_MMAP | | ||
40 | SNDRV_PCM_INFO_INTERLEAVED | | ||
41 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
42 | SNDRV_PCM_INFO_MMAP_VALID | | ||
43 | SNDRV_PCM_INFO_PAUSE | | ||
44 | SNDRV_PCM_INFO_SYNC_START), | ||
45 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
46 | .rates = SNDRV_PCM_RATE_48000, | ||
47 | .rate_min = 48000, | ||
48 | .rate_max = 48000, | ||
49 | .channels_min = 2, | ||
50 | .channels_max = 2, | ||
51 | .buffer_bytes_max = 60000, | ||
52 | .period_bytes_min = 64, | ||
53 | .period_bytes_max = 8192, | ||
54 | .periods_min = 1, | ||
55 | .periods_max = 1024}, | ||
56 | .capture_hw = { | ||
57 | .info = (SNDRV_PCM_INFO_MMAP | | ||
58 | SNDRV_PCM_INFO_INTERLEAVED | | ||
59 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
60 | SNDRV_PCM_INFO_MMAP_VALID | | ||
61 | SNDRV_PCM_INFO_SYNC_START), | ||
62 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, | ||
63 | .rates = SNDRV_PCM_RATE_48000, | ||
64 | .rate_min = 48000, | ||
65 | .rate_max = 48000, | ||
66 | .channels_min = 2, | ||
67 | .channels_max = 2, | ||
68 | .buffer_bytes_max = 60000, | ||
69 | .period_bytes_min = 64, | ||
70 | .period_bytes_max = 8192, | ||
71 | .periods_min = 1, | ||
72 | .periods_max = 1024}, | ||
73 | .rates = { | ||
74 | .nrats = 1, | ||
75 | .rats = &podhd_ratden}, | ||
76 | .bytes_per_frame = PODHD_BYTES_PER_FRAME | ||
77 | }; | ||
78 | |||
79 | /* | ||
80 | Try to init POD HD device. | ||
81 | */ | ||
82 | static int podhd_init(struct usb_line6 *line6, | ||
83 | const struct usb_device_id *id) | ||
84 | { | ||
85 | int err; | ||
86 | |||
87 | /* initialize MIDI subsystem: */ | ||
88 | err = line6_init_midi(line6); | ||
89 | if (err < 0) | ||
90 | return err; | ||
91 | |||
92 | /* initialize PCM subsystem: */ | ||
93 | err = line6_init_pcm(line6, &podhd_pcm_properties); | ||
94 | if (err < 0) | ||
95 | return err; | ||
96 | |||
97 | /* register USB audio system: */ | ||
98 | return snd_card_register(line6->card); | ||
99 | } | ||
100 | |||
101 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) | ||
102 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) | ||
103 | |||
104 | /* table of devices that work with this driver */ | ||
105 | static const struct usb_device_id podhd_id_table[] = { | ||
106 | { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 }, | ||
107 | { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 }, | ||
108 | { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 }, | ||
109 | { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 }, | ||
110 | {} | ||
111 | }; | ||
112 | |||
113 | MODULE_DEVICE_TABLE(usb, podhd_id_table); | ||
114 | |||
115 | static const struct line6_properties podhd_properties_table[] = { | ||
116 | [LINE6_PODHD300] = { | ||
117 | .id = "PODHD300", | ||
118 | .name = "POD HD300", | ||
119 | .capabilities = LINE6_CAP_CONTROL | ||
120 | | LINE6_CAP_PCM | ||
121 | | LINE6_CAP_HWMON, | ||
122 | .altsetting = 5, | ||
123 | .ep_ctrl_r = 0x84, | ||
124 | .ep_ctrl_w = 0x03, | ||
125 | .ep_audio_r = 0x82, | ||
126 | .ep_audio_w = 0x01, | ||
127 | }, | ||
128 | [LINE6_PODHD400] = { | ||
129 | .id = "PODHD400", | ||
130 | .name = "POD HD400", | ||
131 | .capabilities = LINE6_CAP_CONTROL | ||
132 | | LINE6_CAP_PCM | ||
133 | | LINE6_CAP_HWMON, | ||
134 | .altsetting = 5, | ||
135 | .ep_ctrl_r = 0x84, | ||
136 | .ep_ctrl_w = 0x03, | ||
137 | .ep_audio_r = 0x82, | ||
138 | .ep_audio_w = 0x01, | ||
139 | }, | ||
140 | [LINE6_PODHD500_0] = { | ||
141 | .id = "PODHD500", | ||
142 | .name = "POD HD500", | ||
143 | .capabilities = LINE6_CAP_CONTROL | ||
144 | | LINE6_CAP_PCM | ||
145 | | LINE6_CAP_HWMON, | ||
146 | .altsetting = 1, | ||
147 | .ep_ctrl_r = 0x81, | ||
148 | .ep_ctrl_w = 0x01, | ||
149 | .ep_audio_r = 0x86, | ||
150 | .ep_audio_w = 0x02, | ||
151 | }, | ||
152 | [LINE6_PODHD500_1] = { | ||
153 | .id = "PODHD500", | ||
154 | .name = "POD HD500", | ||
155 | .capabilities = LINE6_CAP_CONTROL | ||
156 | | LINE6_CAP_PCM | ||
157 | | LINE6_CAP_HWMON, | ||
158 | .altsetting = 1, | ||
159 | .ep_ctrl_r = 0x81, | ||
160 | .ep_ctrl_w = 0x01, | ||
161 | .ep_audio_r = 0x86, | ||
162 | .ep_audio_w = 0x02, | ||
163 | }, | ||
164 | }; | ||
165 | |||
166 | /* | ||
167 | Probe USB device. | ||
168 | */ | ||
169 | static int podhd_probe(struct usb_interface *interface, | ||
170 | const struct usb_device_id *id) | ||
171 | { | ||
172 | return line6_probe(interface, id, "Line6-PODHD", | ||
173 | &podhd_properties_table[id->driver_info], | ||
174 | podhd_init, sizeof(struct usb_line6)); | ||
175 | } | ||
176 | |||
177 | static struct usb_driver podhd_driver = { | ||
178 | .name = KBUILD_MODNAME, | ||
179 | .probe = podhd_probe, | ||
180 | .disconnect = line6_disconnect, | ||
181 | #ifdef CONFIG_PM | ||
182 | .suspend = line6_suspend, | ||
183 | .resume = line6_resume, | ||
184 | .reset_resume = line6_resume, | ||
185 | #endif | ||
186 | .id_table = podhd_id_table, | ||
187 | }; | ||
188 | |||
189 | module_usb_driver(podhd_driver); | ||
190 | |||
191 | MODULE_DESCRIPTION("Line 6 PODHD USB driver"); | ||
192 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c new file mode 100644 index 000000000000..6d4c50c9b17d --- /dev/null +++ b/sound/usb/line6/toneport.c | |||
@@ -0,0 +1,580 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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 <linux/usb.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/leds.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/control.h> | ||
20 | |||
21 | #include "capture.h" | ||
22 | #include "driver.h" | ||
23 | #include "playback.h" | ||
24 | |||
25 | enum line6_device_type { | ||
26 | LINE6_GUITARPORT, | ||
27 | LINE6_PODSTUDIO_GX, | ||
28 | LINE6_PODSTUDIO_UX1, | ||
29 | LINE6_PODSTUDIO_UX2, | ||
30 | LINE6_TONEPORT_GX, | ||
31 | LINE6_TONEPORT_UX1, | ||
32 | LINE6_TONEPORT_UX2, | ||
33 | }; | ||
34 | |||
35 | struct usb_line6_toneport; | ||
36 | |||
37 | struct toneport_led { | ||
38 | struct led_classdev dev; | ||
39 | char name[64]; | ||
40 | struct usb_line6_toneport *toneport; | ||
41 | bool registered; | ||
42 | }; | ||
43 | |||
44 | struct usb_line6_toneport { | ||
45 | /* Generic Line 6 USB data */ | ||
46 | struct usb_line6 line6; | ||
47 | |||
48 | /* Source selector */ | ||
49 | int source; | ||
50 | |||
51 | /* Serial number of device */ | ||
52 | u32 serial_number; | ||
53 | |||
54 | /* Firmware version (x 100) */ | ||
55 | u8 firmware_version; | ||
56 | |||
57 | /* Timer for delayed PCM startup */ | ||
58 | struct timer_list timer; | ||
59 | |||
60 | /* Device type */ | ||
61 | enum line6_device_type type; | ||
62 | |||
63 | /* LED instances */ | ||
64 | struct toneport_led leds[2]; | ||
65 | }; | ||
66 | |||
67 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); | ||
68 | |||
69 | #define TONEPORT_PCM_DELAY 1 | ||
70 | |||
71 | static struct snd_ratden toneport_ratden = { | ||
72 | .num_min = 44100, | ||
73 | .num_max = 44100, | ||
74 | .num_step = 1, | ||
75 | .den = 1 | ||
76 | }; | ||
77 | |||
78 | static struct line6_pcm_properties toneport_pcm_properties = { | ||
79 | .playback_hw = { | ||
80 | .info = (SNDRV_PCM_INFO_MMAP | | ||
81 | SNDRV_PCM_INFO_INTERLEAVED | | ||
82 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
83 | SNDRV_PCM_INFO_MMAP_VALID | | ||
84 | SNDRV_PCM_INFO_PAUSE | | ||
85 | SNDRV_PCM_INFO_SYNC_START), | ||
86 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
87 | .rates = SNDRV_PCM_RATE_KNOT, | ||
88 | .rate_min = 44100, | ||
89 | .rate_max = 44100, | ||
90 | .channels_min = 2, | ||
91 | .channels_max = 2, | ||
92 | .buffer_bytes_max = 60000, | ||
93 | .period_bytes_min = 64, | ||
94 | .period_bytes_max = 8192, | ||
95 | .periods_min = 1, | ||
96 | .periods_max = 1024}, | ||
97 | .capture_hw = { | ||
98 | .info = (SNDRV_PCM_INFO_MMAP | | ||
99 | SNDRV_PCM_INFO_INTERLEAVED | | ||
100 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
101 | SNDRV_PCM_INFO_MMAP_VALID | | ||
102 | SNDRV_PCM_INFO_SYNC_START), | ||
103 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
104 | .rates = SNDRV_PCM_RATE_KNOT, | ||
105 | .rate_min = 44100, | ||
106 | .rate_max = 44100, | ||
107 | .channels_min = 2, | ||
108 | .channels_max = 2, | ||
109 | .buffer_bytes_max = 60000, | ||
110 | .period_bytes_min = 64, | ||
111 | .period_bytes_max = 8192, | ||
112 | .periods_min = 1, | ||
113 | .periods_max = 1024}, | ||
114 | .rates = { | ||
115 | .nrats = 1, | ||
116 | .rats = &toneport_ratden}, | ||
117 | .bytes_per_frame = 4 | ||
118 | }; | ||
119 | |||
120 | static const struct { | ||
121 | const char *name; | ||
122 | int code; | ||
123 | } toneport_source_info[] = { | ||
124 | {"Microphone", 0x0a01}, | ||
125 | {"Line", 0x0801}, | ||
126 | {"Instrument", 0x0b01}, | ||
127 | {"Inst & Mic", 0x0901} | ||
128 | }; | ||
129 | |||
130 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) | ||
131 | { | ||
132 | int ret; | ||
133 | |||
134 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | ||
135 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | ||
136 | cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); | ||
137 | |||
138 | if (ret < 0) { | ||
139 | dev_err(&usbdev->dev, "send failed (error %d)\n", ret); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | /* monitor info callback */ | ||
147 | static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, | ||
148 | struct snd_ctl_elem_info *uinfo) | ||
149 | { | ||
150 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
151 | uinfo->count = 1; | ||
152 | uinfo->value.integer.min = 0; | ||
153 | uinfo->value.integer.max = 256; | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* monitor get callback */ | ||
158 | static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, | ||
159 | struct snd_ctl_elem_value *ucontrol) | ||
160 | { | ||
161 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
162 | |||
163 | ucontrol->value.integer.value[0] = line6pcm->volume_monitor; | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | /* monitor put callback */ | ||
168 | static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, | ||
169 | struct snd_ctl_elem_value *ucontrol) | ||
170 | { | ||
171 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
172 | int err; | ||
173 | |||
174 | if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) | ||
175 | return 0; | ||
176 | |||
177 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; | ||
178 | |||
179 | if (line6pcm->volume_monitor > 0) { | ||
180 | err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); | ||
181 | if (err < 0) { | ||
182 | line6pcm->volume_monitor = 0; | ||
183 | line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); | ||
184 | return err; | ||
185 | } | ||
186 | } else { | ||
187 | line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); | ||
188 | } | ||
189 | |||
190 | return 1; | ||
191 | } | ||
192 | |||
193 | /* source info callback */ | ||
194 | static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, | ||
195 | struct snd_ctl_elem_info *uinfo) | ||
196 | { | ||
197 | const int size = ARRAY_SIZE(toneport_source_info); | ||
198 | |||
199 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
200 | uinfo->count = 1; | ||
201 | uinfo->value.enumerated.items = size; | ||
202 | |||
203 | if (uinfo->value.enumerated.item >= size) | ||
204 | uinfo->value.enumerated.item = size - 1; | ||
205 | |||
206 | strcpy(uinfo->value.enumerated.name, | ||
207 | toneport_source_info[uinfo->value.enumerated.item].name); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | /* source get callback */ | ||
213 | static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, | ||
214 | struct snd_ctl_elem_value *ucontrol) | ||
215 | { | ||
216 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
217 | struct usb_line6_toneport *toneport = | ||
218 | (struct usb_line6_toneport *)line6pcm->line6; | ||
219 | ucontrol->value.enumerated.item[0] = toneport->source; | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | /* source put callback */ | ||
224 | static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, | ||
225 | struct snd_ctl_elem_value *ucontrol) | ||
226 | { | ||
227 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
228 | struct usb_line6_toneport *toneport = | ||
229 | (struct usb_line6_toneport *)line6pcm->line6; | ||
230 | unsigned int source; | ||
231 | |||
232 | source = ucontrol->value.enumerated.item[0]; | ||
233 | if (source >= ARRAY_SIZE(toneport_source_info)) | ||
234 | return -EINVAL; | ||
235 | if (source == toneport->source) | ||
236 | return 0; | ||
237 | |||
238 | toneport->source = source; | ||
239 | toneport_send_cmd(toneport->line6.usbdev, | ||
240 | toneport_source_info[source].code, 0x0000); | ||
241 | return 1; | ||
242 | } | ||
243 | |||
244 | static void toneport_start_pcm(unsigned long arg) | ||
245 | { | ||
246 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; | ||
247 | struct usb_line6 *line6 = &toneport->line6; | ||
248 | |||
249 | line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR); | ||
250 | } | ||
251 | |||
252 | /* control definition */ | ||
253 | static struct snd_kcontrol_new toneport_control_monitor = { | ||
254 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
255 | .name = "Monitor Playback Volume", | ||
256 | .index = 0, | ||
257 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
258 | .info = snd_toneport_monitor_info, | ||
259 | .get = snd_toneport_monitor_get, | ||
260 | .put = snd_toneport_monitor_put | ||
261 | }; | ||
262 | |||
263 | /* source selector definition */ | ||
264 | static struct snd_kcontrol_new toneport_control_source = { | ||
265 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
266 | .name = "PCM Capture Source", | ||
267 | .index = 0, | ||
268 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
269 | .info = snd_toneport_source_info, | ||
270 | .get = snd_toneport_source_get, | ||
271 | .put = snd_toneport_source_put | ||
272 | }; | ||
273 | |||
274 | /* | ||
275 | For the led on Guitarport. | ||
276 | Brightness goes from 0x00 to 0x26. Set a value above this to have led | ||
277 | blink. | ||
278 | (void cmd_0x02(byte red, byte green) | ||
279 | */ | ||
280 | |||
281 | static bool toneport_has_led(struct usb_line6_toneport *toneport) | ||
282 | { | ||
283 | switch (toneport->type) { | ||
284 | case LINE6_GUITARPORT: | ||
285 | case LINE6_TONEPORT_GX: | ||
286 | /* add your device here if you are missing support for the LEDs */ | ||
287 | return true; | ||
288 | |||
289 | default: | ||
290 | return false; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | static const char * const led_colors[2] = { "red", "green" }; | ||
295 | static const int led_init_vals[2] = { 0x00, 0x26 }; | ||
296 | |||
297 | static void toneport_update_led(struct usb_line6_toneport *toneport) | ||
298 | { | ||
299 | toneport_send_cmd(toneport->line6.usbdev, | ||
300 | (toneport->leds[0].dev.brightness << 8) | 0x0002, | ||
301 | toneport->leds[1].dev.brightness); | ||
302 | } | ||
303 | |||
304 | static void toneport_led_brightness_set(struct led_classdev *led_cdev, | ||
305 | enum led_brightness brightness) | ||
306 | { | ||
307 | struct toneport_led *leds = | ||
308 | container_of(led_cdev, struct toneport_led, dev); | ||
309 | toneport_update_led(leds->toneport); | ||
310 | } | ||
311 | |||
312 | static int toneport_init_leds(struct usb_line6_toneport *toneport) | ||
313 | { | ||
314 | struct device *dev = &toneport->line6.usbdev->dev; | ||
315 | int i, err; | ||
316 | |||
317 | for (i = 0; i < 2; i++) { | ||
318 | struct toneport_led *led = &toneport->leds[i]; | ||
319 | struct led_classdev *leddev = &led->dev; | ||
320 | |||
321 | led->toneport = toneport; | ||
322 | snprintf(led->name, sizeof(led->name), "%s::%s", | ||
323 | dev_name(dev), led_colors[i]); | ||
324 | leddev->name = led->name; | ||
325 | leddev->brightness = led_init_vals[i]; | ||
326 | leddev->max_brightness = 0x26; | ||
327 | leddev->brightness_set = toneport_led_brightness_set; | ||
328 | err = led_classdev_register(dev, leddev); | ||
329 | if (err) | ||
330 | return err; | ||
331 | led->registered = true; | ||
332 | } | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static void toneport_remove_leds(struct usb_line6_toneport *toneport) | ||
338 | { | ||
339 | struct toneport_led *led; | ||
340 | int i; | ||
341 | |||
342 | for (i = 0; i < 2; i++) { | ||
343 | led = &toneport->leds[i]; | ||
344 | if (!led->registered) | ||
345 | break; | ||
346 | led_classdev_unregister(&led->dev); | ||
347 | led->registered = false; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | static bool toneport_has_source_select(struct usb_line6_toneport *toneport) | ||
352 | { | ||
353 | switch (toneport->type) { | ||
354 | case LINE6_TONEPORT_UX1: | ||
355 | case LINE6_TONEPORT_UX2: | ||
356 | case LINE6_PODSTUDIO_UX1: | ||
357 | case LINE6_PODSTUDIO_UX2: | ||
358 | return true; | ||
359 | |||
360 | default: | ||
361 | return false; | ||
362 | } | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | Setup Toneport device. | ||
367 | */ | ||
368 | static void toneport_setup(struct usb_line6_toneport *toneport) | ||
369 | { | ||
370 | int ticks; | ||
371 | struct usb_line6 *line6 = &toneport->line6; | ||
372 | struct usb_device *usbdev = line6->usbdev; | ||
373 | |||
374 | /* sync time on device with host: */ | ||
375 | ticks = (int)get_seconds(); | ||
376 | line6_write_data(line6, 0x80c6, &ticks, 4); | ||
377 | |||
378 | /* enable device: */ | ||
379 | toneport_send_cmd(usbdev, 0x0301, 0x0000); | ||
380 | |||
381 | /* initialize source select: */ | ||
382 | if (toneport_has_source_select(toneport)) | ||
383 | toneport_send_cmd(usbdev, | ||
384 | toneport_source_info[toneport->source].code, | ||
385 | 0x0000); | ||
386 | |||
387 | if (toneport_has_led(toneport)) | ||
388 | toneport_update_led(toneport); | ||
389 | |||
390 | mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); | ||
391 | } | ||
392 | |||
393 | /* | ||
394 | Toneport device disconnected. | ||
395 | */ | ||
396 | static void line6_toneport_disconnect(struct usb_line6 *line6) | ||
397 | { | ||
398 | struct usb_line6_toneport *toneport = | ||
399 | (struct usb_line6_toneport *)line6; | ||
400 | |||
401 | del_timer_sync(&toneport->timer); | ||
402 | |||
403 | if (toneport_has_led(toneport)) | ||
404 | toneport_remove_leds(toneport); | ||
405 | } | ||
406 | |||
407 | |||
408 | /* | ||
409 | Try to init Toneport device. | ||
410 | */ | ||
411 | static int toneport_init(struct usb_line6 *line6, | ||
412 | const struct usb_device_id *id) | ||
413 | { | ||
414 | int err; | ||
415 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; | ||
416 | |||
417 | toneport->type = id->driver_info; | ||
418 | setup_timer(&toneport->timer, toneport_start_pcm, | ||
419 | (unsigned long)toneport); | ||
420 | |||
421 | line6->disconnect = line6_toneport_disconnect; | ||
422 | |||
423 | /* initialize PCM subsystem: */ | ||
424 | err = line6_init_pcm(line6, &toneport_pcm_properties); | ||
425 | if (err < 0) | ||
426 | return err; | ||
427 | |||
428 | /* register monitor control: */ | ||
429 | err = snd_ctl_add(line6->card, | ||
430 | snd_ctl_new1(&toneport_control_monitor, | ||
431 | line6->line6pcm)); | ||
432 | if (err < 0) | ||
433 | return err; | ||
434 | |||
435 | /* register source select control: */ | ||
436 | if (toneport_has_source_select(toneport)) { | ||
437 | err = | ||
438 | snd_ctl_add(line6->card, | ||
439 | snd_ctl_new1(&toneport_control_source, | ||
440 | line6->line6pcm)); | ||
441 | if (err < 0) | ||
442 | return err; | ||
443 | } | ||
444 | |||
445 | line6_read_serial_number(line6, &toneport->serial_number); | ||
446 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); | ||
447 | |||
448 | if (toneport_has_led(toneport)) { | ||
449 | err = toneport_init_leds(toneport); | ||
450 | if (err < 0) | ||
451 | return err; | ||
452 | } | ||
453 | |||
454 | toneport_setup(toneport); | ||
455 | |||
456 | /* register audio system: */ | ||
457 | return snd_card_register(line6->card); | ||
458 | } | ||
459 | |||
460 | #ifdef CONFIG_PM | ||
461 | /* | ||
462 | Resume Toneport device after reset. | ||
463 | */ | ||
464 | static int toneport_reset_resume(struct usb_interface *interface) | ||
465 | { | ||
466 | toneport_setup(usb_get_intfdata(interface)); | ||
467 | return line6_resume(interface); | ||
468 | } | ||
469 | #endif | ||
470 | |||
471 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) | ||
472 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) | ||
473 | |||
474 | /* table of devices that work with this driver */ | ||
475 | static const struct usb_device_id toneport_id_table[] = { | ||
476 | { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, | ||
477 | { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, | ||
478 | { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, | ||
479 | { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, | ||
480 | { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, | ||
481 | { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, | ||
482 | { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, | ||
483 | {} | ||
484 | }; | ||
485 | |||
486 | MODULE_DEVICE_TABLE(usb, toneport_id_table); | ||
487 | |||
488 | static const struct line6_properties toneport_properties_table[] = { | ||
489 | [LINE6_GUITARPORT] = { | ||
490 | .id = "GuitarPort", | ||
491 | .name = "GuitarPort", | ||
492 | .capabilities = LINE6_CAP_PCM, | ||
493 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
494 | /* no control channel */ | ||
495 | .ep_audio_r = 0x82, | ||
496 | .ep_audio_w = 0x01, | ||
497 | }, | ||
498 | [LINE6_PODSTUDIO_GX] = { | ||
499 | .id = "PODStudioGX", | ||
500 | .name = "POD Studio GX", | ||
501 | .capabilities = LINE6_CAP_PCM, | ||
502 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
503 | /* no control channel */ | ||
504 | .ep_audio_r = 0x82, | ||
505 | .ep_audio_w = 0x01, | ||
506 | }, | ||
507 | [LINE6_PODSTUDIO_UX1] = { | ||
508 | .id = "PODStudioUX1", | ||
509 | .name = "POD Studio UX1", | ||
510 | .capabilities = LINE6_CAP_PCM, | ||
511 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
512 | /* no control channel */ | ||
513 | .ep_audio_r = 0x82, | ||
514 | .ep_audio_w = 0x01, | ||
515 | }, | ||
516 | [LINE6_PODSTUDIO_UX2] = { | ||
517 | .id = "PODStudioUX2", | ||
518 | .name = "POD Studio UX2", | ||
519 | .capabilities = LINE6_CAP_PCM, | ||
520 | .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ | ||
521 | /* no control channel */ | ||
522 | .ep_audio_r = 0x82, | ||
523 | .ep_audio_w = 0x01, | ||
524 | }, | ||
525 | [LINE6_TONEPORT_GX] = { | ||
526 | .id = "TonePortGX", | ||
527 | .name = "TonePort GX", | ||
528 | .capabilities = LINE6_CAP_PCM, | ||
529 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
530 | /* no control channel */ | ||
531 | .ep_audio_r = 0x82, | ||
532 | .ep_audio_w = 0x01, | ||
533 | }, | ||
534 | [LINE6_TONEPORT_UX1] = { | ||
535 | .id = "TonePortUX1", | ||
536 | .name = "TonePort UX1", | ||
537 | .capabilities = LINE6_CAP_PCM, | ||
538 | .altsetting = 2, /* 1..4 seem to be ok */ | ||
539 | /* no control channel */ | ||
540 | .ep_audio_r = 0x82, | ||
541 | .ep_audio_w = 0x01, | ||
542 | }, | ||
543 | [LINE6_TONEPORT_UX2] = { | ||
544 | .id = "TonePortUX2", | ||
545 | .name = "TonePort UX2", | ||
546 | .capabilities = LINE6_CAP_PCM, | ||
547 | .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ | ||
548 | /* no control channel */ | ||
549 | .ep_audio_r = 0x82, | ||
550 | .ep_audio_w = 0x01, | ||
551 | }, | ||
552 | }; | ||
553 | |||
554 | /* | ||
555 | Probe USB device. | ||
556 | */ | ||
557 | static int toneport_probe(struct usb_interface *interface, | ||
558 | const struct usb_device_id *id) | ||
559 | { | ||
560 | return line6_probe(interface, id, "Line6-TonePort", | ||
561 | &toneport_properties_table[id->driver_info], | ||
562 | toneport_init, sizeof(struct usb_line6_toneport)); | ||
563 | } | ||
564 | |||
565 | static struct usb_driver toneport_driver = { | ||
566 | .name = KBUILD_MODNAME, | ||
567 | .probe = toneport_probe, | ||
568 | .disconnect = line6_disconnect, | ||
569 | #ifdef CONFIG_PM | ||
570 | .suspend = line6_suspend, | ||
571 | .resume = line6_resume, | ||
572 | .reset_resume = toneport_reset_resume, | ||
573 | #endif | ||
574 | .id_table = toneport_id_table, | ||
575 | }; | ||
576 | |||
577 | module_usb_driver(toneport_driver); | ||
578 | |||
579 | MODULE_DESCRIPTION("TonePort USB driver"); | ||
580 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c new file mode 100644 index 000000000000..ddc23ddf0750 --- /dev/null +++ b/sound/usb/line6/variax.c | |||
@@ -0,0 +1,306 @@ | |||
1 | /* | ||
2 | * Line 6 Linux USB driver | ||
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/spinlock.h> | ||
14 | #include <linux/usb.h> | ||
15 | #include <linux/wait.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <sound/core.h> | ||
18 | |||
19 | #include "driver.h" | ||
20 | |||
21 | #define VARIAX_STARTUP_DELAY1 1000 | ||
22 | #define VARIAX_STARTUP_DELAY3 100 | ||
23 | #define VARIAX_STARTUP_DELAY4 100 | ||
24 | |||
25 | /* | ||
26 | Stages of Variax startup procedure | ||
27 | */ | ||
28 | enum { | ||
29 | VARIAX_STARTUP_INIT = 1, | ||
30 | VARIAX_STARTUP_VERSIONREQ, | ||
31 | VARIAX_STARTUP_WAIT, | ||
32 | VARIAX_STARTUP_ACTIVATE, | ||
33 | VARIAX_STARTUP_WORKQUEUE, | ||
34 | VARIAX_STARTUP_SETUP, | ||
35 | VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1 | ||
36 | }; | ||
37 | |||
38 | enum { | ||
39 | LINE6_PODXTLIVE_VARIAX, | ||
40 | LINE6_VARIAX | ||
41 | }; | ||
42 | |||
43 | struct usb_line6_variax { | ||
44 | /* Generic Line 6 USB data */ | ||
45 | struct usb_line6 line6; | ||
46 | |||
47 | /* Buffer for activation code */ | ||
48 | unsigned char *buffer_activate; | ||
49 | |||
50 | /* Handler for device initialization */ | ||
51 | struct work_struct startup_work; | ||
52 | |||
53 | /* Timers for device initialization */ | ||
54 | struct timer_list startup_timer1; | ||
55 | struct timer_list startup_timer2; | ||
56 | |||
57 | /* Current progress in startup procedure */ | ||
58 | int startup_progress; | ||
59 | }; | ||
60 | |||
61 | #define VARIAX_OFFSET_ACTIVATE 7 | ||
62 | |||
63 | /* | ||
64 | This message is sent by the device during initialization and identifies | ||
65 | the connected guitar version. | ||
66 | */ | ||
67 | static const char variax_init_version[] = { | ||
68 | 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, | ||
69 | 0x07, 0x00, 0x00, 0x00 | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | This message is the last one sent by the device during initialization. | ||
74 | */ | ||
75 | static const char variax_init_done[] = { | ||
76 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b | ||
77 | }; | ||
78 | |||
79 | static const char variax_activate[] = { | ||
80 | 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, | ||
81 | 0xf7 | ||
82 | }; | ||
83 | |||
84 | /* forward declarations: */ | ||
85 | static void variax_startup2(unsigned long data); | ||
86 | static void variax_startup4(unsigned long data); | ||
87 | static void variax_startup5(unsigned long data); | ||
88 | |||
89 | static void variax_activate_async(struct usb_line6_variax *variax, int a) | ||
90 | { | ||
91 | variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; | ||
92 | line6_send_raw_message_async(&variax->line6, variax->buffer_activate, | ||
93 | sizeof(variax_activate)); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | Variax startup procedure. | ||
98 | This is a sequence of functions with special requirements (e.g., must | ||
99 | not run immediately after initialization, must not run in interrupt | ||
100 | context). After the last one has finished, the device is ready to use. | ||
101 | */ | ||
102 | |||
103 | static void variax_startup1(struct usb_line6_variax *variax) | ||
104 | { | ||
105 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); | ||
106 | |||
107 | /* delay startup procedure: */ | ||
108 | line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, | ||
109 | variax_startup2, (unsigned long)variax); | ||
110 | } | ||
111 | |||
112 | static void variax_startup2(unsigned long data) | ||
113 | { | ||
114 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; | ||
115 | struct usb_line6 *line6 = &variax->line6; | ||
116 | |||
117 | /* schedule another startup procedure until startup is complete: */ | ||
118 | if (variax->startup_progress >= VARIAX_STARTUP_LAST) | ||
119 | return; | ||
120 | |||
121 | variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; | ||
122 | line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, | ||
123 | variax_startup2, (unsigned long)variax); | ||
124 | |||
125 | /* request firmware version: */ | ||
126 | line6_version_request_async(line6); | ||
127 | } | ||
128 | |||
129 | static void variax_startup3(struct usb_line6_variax *variax) | ||
130 | { | ||
131 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); | ||
132 | |||
133 | /* delay startup procedure: */ | ||
134 | line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, | ||
135 | variax_startup4, (unsigned long)variax); | ||
136 | } | ||
137 | |||
138 | static void variax_startup4(unsigned long data) | ||
139 | { | ||
140 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; | ||
141 | |||
142 | CHECK_STARTUP_PROGRESS(variax->startup_progress, | ||
143 | VARIAX_STARTUP_ACTIVATE); | ||
144 | |||
145 | /* activate device: */ | ||
146 | variax_activate_async(variax, 1); | ||
147 | line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, | ||
148 | variax_startup5, (unsigned long)variax); | ||
149 | } | ||
150 | |||
151 | static void variax_startup5(unsigned long data) | ||
152 | { | ||
153 | struct usb_line6_variax *variax = (struct usb_line6_variax *)data; | ||
154 | |||
155 | CHECK_STARTUP_PROGRESS(variax->startup_progress, | ||
156 | VARIAX_STARTUP_WORKQUEUE); | ||
157 | |||
158 | /* schedule work for global work queue: */ | ||
159 | schedule_work(&variax->startup_work); | ||
160 | } | ||
161 | |||
162 | static void variax_startup6(struct work_struct *work) | ||
163 | { | ||
164 | struct usb_line6_variax *variax = | ||
165 | container_of(work, struct usb_line6_variax, startup_work); | ||
166 | |||
167 | CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); | ||
168 | |||
169 | /* ALSA audio interface: */ | ||
170 | snd_card_register(variax->line6.card); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | Process a completely received message. | ||
175 | */ | ||
176 | static void line6_variax_process_message(struct usb_line6 *line6) | ||
177 | { | ||
178 | struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; | ||
179 | const unsigned char *buf = variax->line6.buffer_message; | ||
180 | |||
181 | switch (buf[0]) { | ||
182 | case LINE6_RESET: | ||
183 | dev_info(variax->line6.ifcdev, "VARIAX reset\n"); | ||
184 | break; | ||
185 | |||
186 | case LINE6_SYSEX_BEGIN: | ||
187 | if (memcmp(buf + 1, variax_init_version + 1, | ||
188 | sizeof(variax_init_version) - 1) == 0) { | ||
189 | variax_startup3(variax); | ||
190 | } else if (memcmp(buf + 1, variax_init_done + 1, | ||
191 | sizeof(variax_init_done) - 1) == 0) { | ||
192 | /* notify of complete initialization: */ | ||
193 | variax_startup4((unsigned long)variax); | ||
194 | } | ||
195 | break; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | Variax destructor. | ||
201 | */ | ||
202 | static void line6_variax_disconnect(struct usb_line6 *line6) | ||
203 | { | ||
204 | struct usb_line6_variax *variax = (struct usb_line6_variax *)line6; | ||
205 | |||
206 | del_timer(&variax->startup_timer1); | ||
207 | del_timer(&variax->startup_timer2); | ||
208 | cancel_work_sync(&variax->startup_work); | ||
209 | |||
210 | kfree(variax->buffer_activate); | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | Try to init workbench device. | ||
215 | */ | ||
216 | static int variax_init(struct usb_line6 *line6, | ||
217 | const struct usb_device_id *id) | ||
218 | { | ||
219 | struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; | ||
220 | int err; | ||
221 | |||
222 | line6->process_message = line6_variax_process_message; | ||
223 | line6->disconnect = line6_variax_disconnect; | ||
224 | |||
225 | init_timer(&variax->startup_timer1); | ||
226 | init_timer(&variax->startup_timer2); | ||
227 | INIT_WORK(&variax->startup_work, variax_startup6); | ||
228 | |||
229 | /* initialize USB buffers: */ | ||
230 | variax->buffer_activate = kmemdup(variax_activate, | ||
231 | sizeof(variax_activate), GFP_KERNEL); | ||
232 | |||
233 | if (variax->buffer_activate == NULL) | ||
234 | return -ENOMEM; | ||
235 | |||
236 | /* initialize MIDI subsystem: */ | ||
237 | err = line6_init_midi(&variax->line6); | ||
238 | if (err < 0) | ||
239 | return err; | ||
240 | |||
241 | /* initiate startup procedure: */ | ||
242 | variax_startup1(variax); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) | ||
247 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) | ||
248 | |||
249 | /* table of devices that work with this driver */ | ||
250 | static const struct usb_device_id variax_id_table[] = { | ||
251 | { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX }, | ||
252 | { LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX }, | ||
253 | {} | ||
254 | }; | ||
255 | |||
256 | MODULE_DEVICE_TABLE(usb, variax_id_table); | ||
257 | |||
258 | static const struct line6_properties variax_properties_table[] = { | ||
259 | [LINE6_PODXTLIVE_VARIAX] = { | ||
260 | .id = "PODxtLive", | ||
261 | .name = "PODxt Live", | ||
262 | .capabilities = LINE6_CAP_CONTROL, | ||
263 | .altsetting = 1, | ||
264 | .ep_ctrl_r = 0x86, | ||
265 | .ep_ctrl_w = 0x05, | ||
266 | .ep_audio_r = 0x82, | ||
267 | .ep_audio_w = 0x01, | ||
268 | }, | ||
269 | [LINE6_VARIAX] = { | ||
270 | .id = "Variax", | ||
271 | .name = "Variax Workbench", | ||
272 | .capabilities = LINE6_CAP_CONTROL, | ||
273 | .altsetting = 1, | ||
274 | .ep_ctrl_r = 0x82, | ||
275 | .ep_ctrl_w = 0x01, | ||
276 | /* no audio channel */ | ||
277 | } | ||
278 | }; | ||
279 | |||
280 | /* | ||
281 | Probe USB device. | ||
282 | */ | ||
283 | static int variax_probe(struct usb_interface *interface, | ||
284 | const struct usb_device_id *id) | ||
285 | { | ||
286 | return line6_probe(interface, id, "Line6-Variax", | ||
287 | &variax_properties_table[id->driver_info], | ||
288 | variax_init, sizeof(struct usb_line6_variax)); | ||
289 | } | ||
290 | |||
291 | static struct usb_driver variax_driver = { | ||
292 | .name = KBUILD_MODNAME, | ||
293 | .probe = variax_probe, | ||
294 | .disconnect = line6_disconnect, | ||
295 | #ifdef CONFIG_PM | ||
296 | .suspend = line6_suspend, | ||
297 | .resume = line6_resume, | ||
298 | .reset_resume = line6_resume, | ||
299 | #endif | ||
300 | .id_table = variax_id_table, | ||
301 | }; | ||
302 | |||
303 | module_usb_driver(variax_driver); | ||
304 | |||
305 | MODULE_DESCRIPTION("Vairax Workbench USB driver"); | ||
306 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 5bfb695547f8..417ebb11cf48 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c | |||
@@ -2292,14 +2292,13 @@ int snd_usbmidi_create(struct snd_card *card, | |||
2292 | umidi->iface = iface; | 2292 | umidi->iface = iface; |
2293 | umidi->quirk = quirk; | 2293 | umidi->quirk = quirk; |
2294 | umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; | 2294 | umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; |
2295 | init_timer(&umidi->error_timer); | ||
2296 | spin_lock_init(&umidi->disc_lock); | 2295 | spin_lock_init(&umidi->disc_lock); |
2297 | init_rwsem(&umidi->disc_rwsem); | 2296 | init_rwsem(&umidi->disc_rwsem); |
2298 | mutex_init(&umidi->mutex); | 2297 | mutex_init(&umidi->mutex); |
2299 | umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), | 2298 | umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), |
2300 | le16_to_cpu(umidi->dev->descriptor.idProduct)); | 2299 | le16_to_cpu(umidi->dev->descriptor.idProduct)); |
2301 | umidi->error_timer.function = snd_usbmidi_error_timer; | 2300 | setup_timer(&umidi->error_timer, snd_usbmidi_error_timer, |
2302 | umidi->error_timer.data = (unsigned long)umidi; | 2301 | (unsigned long)umidi); |
2303 | 2302 | ||
2304 | /* detect the endpoint(s) to use */ | 2303 | /* detect the endpoint(s) to use */ |
2305 | memset(endpoints, 0, sizeof(endpoints)); | 2304 | memset(endpoints, 0, sizeof(endpoints)); |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 0d8aba5fe1a8..b4ef410e5a98 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -1464,6 +1464,14 @@ static void prepare_playback_urb(struct snd_usb_substream *subs, | |||
1464 | subs->last_frame_number = usb_get_current_frame_number(subs->dev); | 1464 | subs->last_frame_number = usb_get_current_frame_number(subs->dev); |
1465 | subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ | 1465 | subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ |
1466 | 1466 | ||
1467 | if (subs->trigger_tstamp_pending_update) { | ||
1468 | /* this is the first actual URB submitted, | ||
1469 | * update trigger timestamp to reflect actual start time | ||
1470 | */ | ||
1471 | snd_pcm_gettime(runtime, &runtime->trigger_tstamp); | ||
1472 | subs->trigger_tstamp_pending_update = false; | ||
1473 | } | ||
1474 | |||
1467 | spin_unlock_irqrestore(&subs->lock, flags); | 1475 | spin_unlock_irqrestore(&subs->lock, flags); |
1468 | urb->transfer_buffer_length = bytes; | 1476 | urb->transfer_buffer_length = bytes; |
1469 | if (period_elapsed) | 1477 | if (period_elapsed) |
@@ -1550,6 +1558,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea | |||
1550 | 1558 | ||
1551 | switch (cmd) { | 1559 | switch (cmd) { |
1552 | case SNDRV_PCM_TRIGGER_START: | 1560 | case SNDRV_PCM_TRIGGER_START: |
1561 | subs->trigger_tstamp_pending_update = true; | ||
1553 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 1562 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1554 | subs->data_endpoint->prepare_data_urb = prepare_playback_urb; | 1563 | subs->data_endpoint->prepare_data_urb = prepare_playback_urb; |
1555 | subs->data_endpoint->retire_data_urb = retire_playback_urb; | 1564 | subs->data_endpoint->retire_data_urb = retire_playback_urb; |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 0a598af9b38b..67d476548dcf 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -2486,6 +2486,28 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
2486 | } | 2486 | } |
2487 | }, | 2487 | }, |
2488 | 2488 | ||
2489 | { | ||
2490 | /* Akai MPC Element */ | ||
2491 | USB_DEVICE(0x09e8, 0x0021), | ||
2492 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
2493 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2494 | .type = QUIRK_COMPOSITE, | ||
2495 | .data = & (const struct snd_usb_audio_quirk[]) { | ||
2496 | { | ||
2497 | .ifnum = 0, | ||
2498 | .type = QUIRK_IGNORE_INTERFACE | ||
2499 | }, | ||
2500 | { | ||
2501 | .ifnum = 1, | ||
2502 | .type = QUIRK_MIDI_STANDARD_INTERFACE | ||
2503 | }, | ||
2504 | { | ||
2505 | .ifnum = -1 | ||
2506 | } | ||
2507 | } | ||
2508 | } | ||
2509 | }, | ||
2510 | |||
2489 | /* TerraTec devices */ | 2511 | /* TerraTec devices */ |
2490 | { | 2512 | { |
2491 | USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), | 2513 | USB_DEVICE_VENDOR_SPEC(0x0ccd, 0x0012), |
diff --git a/sound/usb/usx2y/usb_stream.h b/sound/usb/usx2y/usb_stream.h index 4dd74ab1e9cc..90369001eab6 100644 --- a/sound/usb/usx2y/usb_stream.h +++ b/sound/usb/usx2y/usb_stream.h | |||
@@ -1,76 +1,7 @@ | |||
1 | /* | 1 | #ifndef __USB_STREAM_H |
2 | * Copyright (C) 2007, 2008 Karsten Wiese <fzu@wemgehoertderstaat.de> | 2 | #define __USB_STREAM_H |
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but | ||
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | ||
11 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
12 | * for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software Foundation, | ||
16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
17 | */ | ||
18 | 3 | ||
19 | #define USB_STREAM_INTERFACE_VERSION 2 | 4 | #include <uapi/sound/usb_stream.h> |
20 | |||
21 | #define SNDRV_USB_STREAM_IOCTL_SET_PARAMS \ | ||
22 | _IOW('H', 0x90, struct usb_stream_config) | ||
23 | |||
24 | struct usb_stream_packet { | ||
25 | unsigned offset; | ||
26 | unsigned length; | ||
27 | }; | ||
28 | |||
29 | |||
30 | struct usb_stream_config { | ||
31 | unsigned version; | ||
32 | unsigned sample_rate; | ||
33 | unsigned period_frames; | ||
34 | unsigned frame_size; | ||
35 | }; | ||
36 | |||
37 | struct usb_stream { | ||
38 | struct usb_stream_config cfg; | ||
39 | unsigned read_size; | ||
40 | unsigned write_size; | ||
41 | |||
42 | int period_size; | ||
43 | |||
44 | unsigned state; | ||
45 | |||
46 | int idle_insize; | ||
47 | int idle_outsize; | ||
48 | int sync_packet; | ||
49 | unsigned insize_done; | ||
50 | unsigned periods_done; | ||
51 | unsigned periods_polled; | ||
52 | |||
53 | struct usb_stream_packet outpacket[2]; | ||
54 | unsigned inpackets; | ||
55 | unsigned inpacket_head; | ||
56 | unsigned inpacket_split; | ||
57 | unsigned inpacket_split_at; | ||
58 | unsigned next_inpacket_split; | ||
59 | unsigned next_inpacket_split_at; | ||
60 | struct usb_stream_packet inpacket[0]; | ||
61 | }; | ||
62 | |||
63 | enum usb_stream_state { | ||
64 | usb_stream_invalid, | ||
65 | usb_stream_stopped, | ||
66 | usb_stream_sync0, | ||
67 | usb_stream_sync1, | ||
68 | usb_stream_ready, | ||
69 | usb_stream_running, | ||
70 | usb_stream_xrun, | ||
71 | }; | ||
72 | |||
73 | #if __KERNEL__ | ||
74 | 5 | ||
75 | #define USB_STREAM_NURBS 4 | 6 | #define USB_STREAM_NURBS 4 |
76 | #define USB_STREAM_URBDEPTH 4 | 7 | #define USB_STREAM_URBDEPTH 4 |
@@ -108,5 +39,4 @@ void usb_stream_free(struct usb_stream_kernel *); | |||
108 | int usb_stream_start(struct usb_stream_kernel *); | 39 | int usb_stream_start(struct usb_stream_kernel *); |
109 | void usb_stream_stop(struct usb_stream_kernel *); | 40 | void usb_stream_stop(struct usb_stream_kernel *); |
110 | 41 | ||
111 | 42 | #endif /* __USB_STREAM_H */ | |
112 | #endif | ||