Commit 597a1e7cccc9a5a0c47629267ac4b23bf8654578
Committed by
Greg Kroah-Hartman
1 parent
fb657461ab
Exists in
master
and in
7 other branches
staging/line6: Fix sparse warning 'Using plain integer as NULL pointer'
This patch fixes the warning generated by sparse: "Using plain integer as NULL pointer" by replacing the offending 0s with NULL. Signed-off-by: Peter Huewe <peterhuewe@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Showing 3 changed files with 4 additions and 4 deletions Inline Diff
drivers/staging/line6/capture.c
1 | /* | 1 | /* |
2 | * Line6 Linux USB driver - 0.9.1beta | 2 | * Line6 Linux USB driver - 0.9.1beta |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 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 | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation, version 2. | 8 | * published by the Free Software Foundation, version 2. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <sound/core.h> | 12 | #include <sound/core.h> |
13 | #include <sound/pcm.h> | 13 | #include <sound/pcm.h> |
14 | #include <sound/pcm_params.h> | 14 | #include <sound/pcm_params.h> |
15 | 15 | ||
16 | #include "audio.h" | 16 | #include "audio.h" |
17 | #include "capture.h" | 17 | #include "capture.h" |
18 | #include "driver.h" | 18 | #include "driver.h" |
19 | #include "pcm.h" | 19 | #include "pcm.h" |
20 | #include "pod.h" | 20 | #include "pod.h" |
21 | 21 | ||
22 | /* | 22 | /* |
23 | Find a free URB and submit it. | 23 | Find a free URB and submit it. |
24 | */ | 24 | */ |
25 | static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) | 25 | static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm) |
26 | { | 26 | { |
27 | int index; | 27 | int index; |
28 | unsigned long flags; | 28 | unsigned long flags; |
29 | int i, urb_size; | 29 | int i, urb_size; |
30 | int ret; | 30 | int ret; |
31 | struct urb *urb_in; | 31 | struct urb *urb_in; |
32 | 32 | ||
33 | spin_lock_irqsave(&line6pcm->lock_audio_in, flags); | 33 | spin_lock_irqsave(&line6pcm->lock_audio_in, flags); |
34 | index = | 34 | index = |
35 | find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); | 35 | find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS); |
36 | 36 | ||
37 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { | 37 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { |
38 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); | 38 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); |
39 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); | 39 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); |
40 | return -EINVAL; | 40 | return -EINVAL; |
41 | } | 41 | } |
42 | 42 | ||
43 | urb_in = line6pcm->urb_audio_in[index]; | 43 | urb_in = line6pcm->urb_audio_in[index]; |
44 | urb_size = 0; | 44 | urb_size = 0; |
45 | 45 | ||
46 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | 46 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { |
47 | struct usb_iso_packet_descriptor *fin = | 47 | struct usb_iso_packet_descriptor *fin = |
48 | &urb_in->iso_frame_desc[i]; | 48 | &urb_in->iso_frame_desc[i]; |
49 | fin->offset = urb_size; | 49 | fin->offset = urb_size; |
50 | fin->length = line6pcm->max_packet_size; | 50 | fin->length = line6pcm->max_packet_size; |
51 | urb_size += line6pcm->max_packet_size; | 51 | urb_size += line6pcm->max_packet_size; |
52 | } | 52 | } |
53 | 53 | ||
54 | urb_in->transfer_buffer = | 54 | urb_in->transfer_buffer = |
55 | line6pcm->buffer_in + | 55 | line6pcm->buffer_in + |
56 | index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; | 56 | index * LINE6_ISO_PACKETS * line6pcm->max_packet_size; |
57 | urb_in->transfer_buffer_length = urb_size; | 57 | urb_in->transfer_buffer_length = urb_size; |
58 | urb_in->context = line6pcm; | 58 | urb_in->context = line6pcm; |
59 | 59 | ||
60 | ret = usb_submit_urb(urb_in, GFP_ATOMIC); | 60 | ret = usb_submit_urb(urb_in, GFP_ATOMIC); |
61 | 61 | ||
62 | if (ret == 0) | 62 | if (ret == 0) |
63 | set_bit(index, &line6pcm->active_urb_in); | 63 | set_bit(index, &line6pcm->active_urb_in); |
64 | else | 64 | else |
65 | dev_err(line6pcm->line6->ifcdev, | 65 | dev_err(line6pcm->line6->ifcdev, |
66 | "URB in #%d submission failed (%d)\n", index, ret); | 66 | "URB in #%d submission failed (%d)\n", index, ret); |
67 | 67 | ||
68 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); | 68 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); |
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | /* | 72 | /* |
73 | Submit all currently available capture URBs. | 73 | Submit all currently available capture URBs. |
74 | */ | 74 | */ |
75 | int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) | 75 | int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm) |
76 | { | 76 | { |
77 | int ret, i; | 77 | int ret, i; |
78 | 78 | ||
79 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | 79 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { |
80 | ret = submit_audio_in_urb(line6pcm); | 80 | ret = submit_audio_in_urb(line6pcm); |
81 | if (ret < 0) | 81 | if (ret < 0) |
82 | return ret; | 82 | return ret; |
83 | } | 83 | } |
84 | 84 | ||
85 | return 0; | 85 | return 0; |
86 | } | 86 | } |
87 | 87 | ||
88 | /* | 88 | /* |
89 | Unlink all currently active capture URBs. | 89 | Unlink all currently active capture URBs. |
90 | */ | 90 | */ |
91 | void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) | 91 | void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm) |
92 | { | 92 | { |
93 | unsigned int i; | 93 | unsigned int i; |
94 | 94 | ||
95 | for (i = LINE6_ISO_BUFFERS; i--;) { | 95 | for (i = LINE6_ISO_BUFFERS; i--;) { |
96 | if (test_bit(i, &line6pcm->active_urb_in)) { | 96 | if (test_bit(i, &line6pcm->active_urb_in)) { |
97 | if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { | 97 | if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) { |
98 | struct urb *u = line6pcm->urb_audio_in[i]; | 98 | struct urb *u = line6pcm->urb_audio_in[i]; |
99 | usb_unlink_urb(u); | 99 | usb_unlink_urb(u); |
100 | } | 100 | } |
101 | } | 101 | } |
102 | } | 102 | } |
103 | } | 103 | } |
104 | 104 | ||
105 | /* | 105 | /* |
106 | Wait until unlinking of all currently active capture URBs has been | 106 | Wait until unlinking of all currently active capture URBs has been |
107 | finished. | 107 | finished. |
108 | */ | 108 | */ |
109 | static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) | 109 | static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) |
110 | { | 110 | { |
111 | int timeout = HZ; | 111 | int timeout = HZ; |
112 | unsigned int i; | 112 | unsigned int i; |
113 | int alive; | 113 | int alive; |
114 | 114 | ||
115 | do { | 115 | do { |
116 | alive = 0; | 116 | alive = 0; |
117 | for (i = LINE6_ISO_BUFFERS; i--;) { | 117 | for (i = LINE6_ISO_BUFFERS; i--;) { |
118 | if (test_bit(i, &line6pcm->active_urb_in)) | 118 | if (test_bit(i, &line6pcm->active_urb_in)) |
119 | alive++; | 119 | alive++; |
120 | } | 120 | } |
121 | if (!alive) | 121 | if (!alive) |
122 | break; | 122 | break; |
123 | set_current_state(TASK_UNINTERRUPTIBLE); | 123 | set_current_state(TASK_UNINTERRUPTIBLE); |
124 | schedule_timeout(1); | 124 | schedule_timeout(1); |
125 | } while (--timeout > 0); | 125 | } while (--timeout > 0); |
126 | if (alive) | 126 | if (alive) |
127 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); | 127 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); |
128 | } | 128 | } |
129 | 129 | ||
130 | /* | 130 | /* |
131 | Unlink all currently active capture URBs, and wait for finishing. | 131 | Unlink all currently active capture URBs, and wait for finishing. |
132 | */ | 132 | */ |
133 | void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) | 133 | void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm) |
134 | { | 134 | { |
135 | line6_unlink_audio_in_urbs(line6pcm); | 135 | line6_unlink_audio_in_urbs(line6pcm); |
136 | wait_clear_audio_in_urbs(line6pcm); | 136 | wait_clear_audio_in_urbs(line6pcm); |
137 | } | 137 | } |
138 | 138 | ||
139 | /* | 139 | /* |
140 | Copy data into ALSA capture buffer. | 140 | Copy data into ALSA capture buffer. |
141 | */ | 141 | */ |
142 | void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) | 142 | void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize) |
143 | { | 143 | { |
144 | struct snd_pcm_substream *substream = | 144 | struct snd_pcm_substream *substream = |
145 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); | 145 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); |
146 | struct snd_pcm_runtime *runtime = substream->runtime; | 146 | struct snd_pcm_runtime *runtime = substream->runtime; |
147 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; | 147 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; |
148 | int frames = fsize / bytes_per_frame; | 148 | int frames = fsize / bytes_per_frame; |
149 | 149 | ||
150 | if (runtime == 0) | 150 | if (runtime == NULL) |
151 | return; | 151 | return; |
152 | 152 | ||
153 | if (line6pcm->pos_in_done + frames > runtime->buffer_size) { | 153 | if (line6pcm->pos_in_done + frames > runtime->buffer_size) { |
154 | /* | 154 | /* |
155 | The transferred area goes over buffer boundary, | 155 | The transferred area goes over buffer boundary, |
156 | copy two separate chunks. | 156 | copy two separate chunks. |
157 | */ | 157 | */ |
158 | int len; | 158 | int len; |
159 | len = runtime->buffer_size - line6pcm->pos_in_done; | 159 | len = runtime->buffer_size - line6pcm->pos_in_done; |
160 | 160 | ||
161 | if (len > 0) { | 161 | if (len > 0) { |
162 | memcpy(runtime->dma_area + | 162 | memcpy(runtime->dma_area + |
163 | line6pcm->pos_in_done * bytes_per_frame, fbuf, | 163 | line6pcm->pos_in_done * bytes_per_frame, fbuf, |
164 | len * bytes_per_frame); | 164 | len * bytes_per_frame); |
165 | memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, | 165 | memcpy(runtime->dma_area, fbuf + len * bytes_per_frame, |
166 | (frames - len) * bytes_per_frame); | 166 | (frames - len) * bytes_per_frame); |
167 | } else { | 167 | } else { |
168 | /* this is somewhat paranoid */ | 168 | /* this is somewhat paranoid */ |
169 | dev_err(line6pcm->line6->ifcdev, | 169 | dev_err(line6pcm->line6->ifcdev, |
170 | "driver bug: len = %d\n", len); | 170 | "driver bug: len = %d\n", len); |
171 | } | 171 | } |
172 | } else { | 172 | } else { |
173 | /* copy single chunk */ | 173 | /* copy single chunk */ |
174 | memcpy(runtime->dma_area + | 174 | memcpy(runtime->dma_area + |
175 | line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); | 175 | line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize); |
176 | } | 176 | } |
177 | 177 | ||
178 | line6pcm->pos_in_done += frames; | 178 | line6pcm->pos_in_done += frames; |
179 | if (line6pcm->pos_in_done >= runtime->buffer_size) | 179 | if (line6pcm->pos_in_done >= runtime->buffer_size) |
180 | line6pcm->pos_in_done -= runtime->buffer_size; | 180 | line6pcm->pos_in_done -= runtime->buffer_size; |
181 | } | 181 | } |
182 | 182 | ||
183 | void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) | 183 | void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length) |
184 | { | 184 | { |
185 | struct snd_pcm_substream *substream = | 185 | struct snd_pcm_substream *substream = |
186 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); | 186 | get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE); |
187 | 187 | ||
188 | line6pcm->bytes_in += length; | 188 | line6pcm->bytes_in += length; |
189 | if (line6pcm->bytes_in >= line6pcm->period_in) { | 189 | if (line6pcm->bytes_in >= line6pcm->period_in) { |
190 | line6pcm->bytes_in %= line6pcm->period_in; | 190 | line6pcm->bytes_in %= line6pcm->period_in; |
191 | snd_pcm_period_elapsed(substream); | 191 | snd_pcm_period_elapsed(substream); |
192 | } | 192 | } |
193 | } | 193 | } |
194 | 194 | ||
195 | /* | 195 | /* |
196 | * Callback for completed capture URB. | 196 | * Callback for completed capture URB. |
197 | */ | 197 | */ |
198 | static void audio_in_callback(struct urb *urb) | 198 | static void audio_in_callback(struct urb *urb) |
199 | { | 199 | { |
200 | int i, index, length = 0, shutdown = 0; | 200 | int i, index, length = 0, shutdown = 0; |
201 | unsigned long flags; | 201 | unsigned long flags; |
202 | 202 | ||
203 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; | 203 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; |
204 | 204 | ||
205 | line6pcm->last_frame_in = urb->start_frame; | 205 | line6pcm->last_frame_in = urb->start_frame; |
206 | 206 | ||
207 | /* find index of URB */ | 207 | /* find index of URB */ |
208 | for (index = 0; index < LINE6_ISO_BUFFERS; ++index) | 208 | for (index = 0; index < LINE6_ISO_BUFFERS; ++index) |
209 | if (urb == line6pcm->urb_audio_in[index]) | 209 | if (urb == line6pcm->urb_audio_in[index]) |
210 | break; | 210 | break; |
211 | 211 | ||
212 | #ifdef CONFIG_LINE6_USB_DUMP_PCM | 212 | #ifdef CONFIG_LINE6_USB_DUMP_PCM |
213 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | 213 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { |
214 | struct usb_iso_packet_descriptor *fout = | 214 | struct usb_iso_packet_descriptor *fout = |
215 | &urb->iso_frame_desc[i]; | 215 | &urb->iso_frame_desc[i]; |
216 | line6_write_hexdump(line6pcm->line6, 'C', | 216 | line6_write_hexdump(line6pcm->line6, 'C', |
217 | urb->transfer_buffer + fout->offset, | 217 | urb->transfer_buffer + fout->offset, |
218 | fout->length); | 218 | fout->length); |
219 | } | 219 | } |
220 | #endif | 220 | #endif |
221 | 221 | ||
222 | spin_lock_irqsave(&line6pcm->lock_audio_in, flags); | 222 | spin_lock_irqsave(&line6pcm->lock_audio_in, flags); |
223 | 223 | ||
224 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | 224 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { |
225 | char *fbuf; | 225 | char *fbuf; |
226 | int fsize; | 226 | int fsize; |
227 | struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; | 227 | struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i]; |
228 | 228 | ||
229 | if (fin->status == -EXDEV) { | 229 | if (fin->status == -EXDEV) { |
230 | shutdown = 1; | 230 | shutdown = 1; |
231 | break; | 231 | break; |
232 | } | 232 | } |
233 | 233 | ||
234 | fbuf = urb->transfer_buffer + fin->offset; | 234 | fbuf = urb->transfer_buffer + fin->offset; |
235 | fsize = fin->actual_length; | 235 | fsize = fin->actual_length; |
236 | 236 | ||
237 | if (fsize > line6pcm->max_packet_size) { | 237 | if (fsize > line6pcm->max_packet_size) { |
238 | dev_err(line6pcm->line6->ifcdev, | 238 | dev_err(line6pcm->line6->ifcdev, |
239 | "driver and/or device bug: packet too large (%d > %d)\n", | 239 | "driver and/or device bug: packet too large (%d > %d)\n", |
240 | fsize, line6pcm->max_packet_size); | 240 | fsize, line6pcm->max_packet_size); |
241 | } | 241 | } |
242 | 242 | ||
243 | length += fsize; | 243 | length += fsize; |
244 | 244 | ||
245 | /* the following assumes LINE6_ISO_PACKETS == 1: */ | 245 | /* the following assumes LINE6_ISO_PACKETS == 1: */ |
246 | #if LINE6_BACKUP_MONITOR_SIGNAL | 246 | #if LINE6_BACKUP_MONITOR_SIGNAL |
247 | memcpy(line6pcm->prev_fbuf, fbuf, fsize); | 247 | memcpy(line6pcm->prev_fbuf, fbuf, fsize); |
248 | #else | 248 | #else |
249 | line6pcm->prev_fbuf = fbuf; | 249 | line6pcm->prev_fbuf = fbuf; |
250 | #endif | 250 | #endif |
251 | line6pcm->prev_fsize = fsize; | 251 | line6pcm->prev_fsize = fsize; |
252 | 252 | ||
253 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | 253 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
254 | if (!(line6pcm->flags & MASK_PCM_IMPULSE)) | 254 | if (!(line6pcm->flags & MASK_PCM_IMPULSE)) |
255 | #endif | 255 | #endif |
256 | if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags) | 256 | if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags) |
257 | && (fsize > 0)) | 257 | && (fsize > 0)) |
258 | line6_capture_copy(line6pcm, fbuf, fsize); | 258 | line6_capture_copy(line6pcm, fbuf, fsize); |
259 | } | 259 | } |
260 | 260 | ||
261 | clear_bit(index, &line6pcm->active_urb_in); | 261 | clear_bit(index, &line6pcm->active_urb_in); |
262 | 262 | ||
263 | if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) | 263 | if (test_and_clear_bit(index, &line6pcm->unlink_urb_in)) |
264 | shutdown = 1; | 264 | shutdown = 1; |
265 | 265 | ||
266 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); | 266 | spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags); |
267 | 267 | ||
268 | if (!shutdown) { | 268 | if (!shutdown) { |
269 | submit_audio_in_urb(line6pcm); | 269 | submit_audio_in_urb(line6pcm); |
270 | 270 | ||
271 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | 271 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
272 | if (!(line6pcm->flags & MASK_PCM_IMPULSE)) | 272 | if (!(line6pcm->flags & MASK_PCM_IMPULSE)) |
273 | #endif | 273 | #endif |
274 | if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags)) | 274 | if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags)) |
275 | line6_capture_check_period(line6pcm, length); | 275 | line6_capture_check_period(line6pcm, length); |
276 | } | 276 | } |
277 | } | 277 | } |
278 | 278 | ||
279 | /* open capture callback */ | 279 | /* open capture callback */ |
280 | static int snd_line6_capture_open(struct snd_pcm_substream *substream) | 280 | static int snd_line6_capture_open(struct snd_pcm_substream *substream) |
281 | { | 281 | { |
282 | int err; | 282 | int err; |
283 | struct snd_pcm_runtime *runtime = substream->runtime; | 283 | struct snd_pcm_runtime *runtime = substream->runtime; |
284 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 284 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
285 | 285 | ||
286 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, | 286 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, |
287 | SNDRV_PCM_HW_PARAM_RATE, | 287 | SNDRV_PCM_HW_PARAM_RATE, |
288 | (&line6pcm-> | 288 | (&line6pcm-> |
289 | properties->snd_line6_rates)); | 289 | properties->snd_line6_rates)); |
290 | if (err < 0) | 290 | if (err < 0) |
291 | return err; | 291 | return err; |
292 | 292 | ||
293 | runtime->hw = line6pcm->properties->snd_line6_capture_hw; | 293 | runtime->hw = line6pcm->properties->snd_line6_capture_hw; |
294 | return 0; | 294 | return 0; |
295 | } | 295 | } |
296 | 296 | ||
297 | /* close capture callback */ | 297 | /* close capture callback */ |
298 | static int snd_line6_capture_close(struct snd_pcm_substream *substream) | 298 | static int snd_line6_capture_close(struct snd_pcm_substream *substream) |
299 | { | 299 | { |
300 | return 0; | 300 | return 0; |
301 | } | 301 | } |
302 | 302 | ||
303 | /* hw_params capture callback */ | 303 | /* hw_params capture callback */ |
304 | static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, | 304 | static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream, |
305 | struct snd_pcm_hw_params *hw_params) | 305 | struct snd_pcm_hw_params *hw_params) |
306 | { | 306 | { |
307 | int ret; | 307 | int ret; |
308 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 308 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
309 | 309 | ||
310 | /* -- Florian Demski [FD] */ | 310 | /* -- Florian Demski [FD] */ |
311 | /* don't ask me why, but this fixes the bug on my machine */ | 311 | /* don't ask me why, but this fixes the bug on my machine */ |
312 | if (line6pcm == NULL) { | 312 | if (line6pcm == NULL) { |
313 | if (substream->pcm == NULL) | 313 | if (substream->pcm == NULL) |
314 | return -ENOMEM; | 314 | return -ENOMEM; |
315 | if (substream->pcm->private_data == NULL) | 315 | if (substream->pcm->private_data == NULL) |
316 | return -ENOMEM; | 316 | return -ENOMEM; |
317 | substream->private_data = substream->pcm->private_data; | 317 | substream->private_data = substream->pcm->private_data; |
318 | line6pcm = snd_pcm_substream_chip(substream); | 318 | line6pcm = snd_pcm_substream_chip(substream); |
319 | } | 319 | } |
320 | /* -- [FD] end */ | 320 | /* -- [FD] end */ |
321 | 321 | ||
322 | ret = snd_pcm_lib_malloc_pages(substream, | 322 | ret = snd_pcm_lib_malloc_pages(substream, |
323 | params_buffer_bytes(hw_params)); | 323 | params_buffer_bytes(hw_params)); |
324 | if (ret < 0) | 324 | if (ret < 0) |
325 | return ret; | 325 | return ret; |
326 | 326 | ||
327 | line6pcm->period_in = params_period_bytes(hw_params); | 327 | line6pcm->period_in = params_period_bytes(hw_params); |
328 | return 0; | 328 | return 0; |
329 | } | 329 | } |
330 | 330 | ||
331 | /* hw_free capture callback */ | 331 | /* hw_free capture callback */ |
332 | static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) | 332 | static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream) |
333 | { | 333 | { |
334 | return snd_pcm_lib_free_pages(substream); | 334 | return snd_pcm_lib_free_pages(substream); |
335 | } | 335 | } |
336 | 336 | ||
337 | /* trigger callback */ | 337 | /* trigger callback */ |
338 | int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) | 338 | int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) |
339 | { | 339 | { |
340 | int err; | 340 | int err; |
341 | 341 | ||
342 | switch (cmd) { | 342 | switch (cmd) { |
343 | case SNDRV_PCM_TRIGGER_START: | 343 | case SNDRV_PCM_TRIGGER_START: |
344 | #ifdef CONFIG_PM | 344 | #ifdef CONFIG_PM |
345 | case SNDRV_PCM_TRIGGER_RESUME: | 345 | case SNDRV_PCM_TRIGGER_RESUME: |
346 | #endif | 346 | #endif |
347 | err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE); | 347 | err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE); |
348 | 348 | ||
349 | if (err < 0) | 349 | if (err < 0) |
350 | return err; | 350 | return err; |
351 | 351 | ||
352 | break; | 352 | break; |
353 | 353 | ||
354 | case SNDRV_PCM_TRIGGER_STOP: | 354 | case SNDRV_PCM_TRIGGER_STOP: |
355 | #ifdef CONFIG_PM | 355 | #ifdef CONFIG_PM |
356 | case SNDRV_PCM_TRIGGER_SUSPEND: | 356 | case SNDRV_PCM_TRIGGER_SUSPEND: |
357 | #endif | 357 | #endif |
358 | err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE); | 358 | err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE); |
359 | 359 | ||
360 | if (err < 0) | 360 | if (err < 0) |
361 | return err; | 361 | return err; |
362 | 362 | ||
363 | break; | 363 | break; |
364 | 364 | ||
365 | default: | 365 | default: |
366 | return -EINVAL; | 366 | return -EINVAL; |
367 | } | 367 | } |
368 | 368 | ||
369 | return 0; | 369 | return 0; |
370 | } | 370 | } |
371 | 371 | ||
372 | /* capture pointer callback */ | 372 | /* capture pointer callback */ |
373 | static snd_pcm_uframes_t | 373 | static snd_pcm_uframes_t |
374 | snd_line6_capture_pointer(struct snd_pcm_substream *substream) | 374 | snd_line6_capture_pointer(struct snd_pcm_substream *substream) |
375 | { | 375 | { |
376 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 376 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
377 | return line6pcm->pos_in_done; | 377 | return line6pcm->pos_in_done; |
378 | } | 378 | } |
379 | 379 | ||
380 | /* capture operators */ | 380 | /* capture operators */ |
381 | struct snd_pcm_ops snd_line6_capture_ops = { | 381 | struct snd_pcm_ops snd_line6_capture_ops = { |
382 | .open = snd_line6_capture_open, | 382 | .open = snd_line6_capture_open, |
383 | .close = snd_line6_capture_close, | 383 | .close = snd_line6_capture_close, |
384 | .ioctl = snd_pcm_lib_ioctl, | 384 | .ioctl = snd_pcm_lib_ioctl, |
385 | .hw_params = snd_line6_capture_hw_params, | 385 | .hw_params = snd_line6_capture_hw_params, |
386 | .hw_free = snd_line6_capture_hw_free, | 386 | .hw_free = snd_line6_capture_hw_free, |
387 | .prepare = snd_line6_prepare, | 387 | .prepare = snd_line6_prepare, |
388 | .trigger = snd_line6_trigger, | 388 | .trigger = snd_line6_trigger, |
389 | .pointer = snd_line6_capture_pointer, | 389 | .pointer = snd_line6_capture_pointer, |
390 | }; | 390 | }; |
391 | 391 | ||
392 | int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) | 392 | int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) |
393 | { | 393 | { |
394 | int i; | 394 | int i; |
395 | 395 | ||
396 | /* create audio URBs and fill in constant values: */ | 396 | /* create audio URBs and fill in constant values: */ |
397 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | 397 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { |
398 | struct urb *urb; | 398 | struct urb *urb; |
399 | 399 | ||
400 | /* URB for audio in: */ | 400 | /* URB for audio in: */ |
401 | urb = line6pcm->urb_audio_in[i] = | 401 | urb = line6pcm->urb_audio_in[i] = |
402 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); | 402 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); |
403 | 403 | ||
404 | if (urb == NULL) { | 404 | if (urb == NULL) { |
405 | dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); | 405 | dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); |
406 | return -ENOMEM; | 406 | return -ENOMEM; |
407 | } | 407 | } |
408 | 408 | ||
409 | urb->dev = line6pcm->line6->usbdev; | 409 | urb->dev = line6pcm->line6->usbdev; |
410 | urb->pipe = | 410 | urb->pipe = |
411 | usb_rcvisocpipe(line6pcm->line6->usbdev, | 411 | usb_rcvisocpipe(line6pcm->line6->usbdev, |
412 | line6pcm->ep_audio_read & | 412 | line6pcm->ep_audio_read & |
413 | USB_ENDPOINT_NUMBER_MASK); | 413 | USB_ENDPOINT_NUMBER_MASK); |
414 | urb->transfer_flags = URB_ISO_ASAP; | 414 | urb->transfer_flags = URB_ISO_ASAP; |
415 | urb->start_frame = -1; | 415 | urb->start_frame = -1; |
416 | urb->number_of_packets = LINE6_ISO_PACKETS; | 416 | urb->number_of_packets = LINE6_ISO_PACKETS; |
417 | urb->interval = LINE6_ISO_INTERVAL; | 417 | urb->interval = LINE6_ISO_INTERVAL; |
418 | urb->error_count = 0; | 418 | urb->error_count = 0; |
419 | urb->complete = audio_in_callback; | 419 | urb->complete = audio_in_callback; |
420 | } | 420 | } |
421 | 421 | ||
422 | return 0; | 422 | return 0; |
423 | } | 423 | } |
424 | 424 |
drivers/staging/line6/midi.c
1 | /* | 1 | /* |
2 | * Line6 Linux USB driver - 0.9.1beta | 2 | * Line6 Linux USB driver - 0.9.1beta |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 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 | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation, version 2. | 8 | * published by the Free Software Foundation, version 2. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/slab.h> | 12 | #include <linux/slab.h> |
13 | #include <linux/usb.h> | 13 | #include <linux/usb.h> |
14 | #include <sound/core.h> | 14 | #include <sound/core.h> |
15 | #include <sound/rawmidi.h> | 15 | #include <sound/rawmidi.h> |
16 | 16 | ||
17 | #include "audio.h" | 17 | #include "audio.h" |
18 | #include "driver.h" | 18 | #include "driver.h" |
19 | #include "midi.h" | 19 | #include "midi.h" |
20 | #include "pod.h" | 20 | #include "pod.h" |
21 | #include "usbdefs.h" | 21 | #include "usbdefs.h" |
22 | 22 | ||
23 | #define line6_rawmidi_substream_midi(substream) \ | 23 | #define line6_rawmidi_substream_midi(substream) \ |
24 | ((struct snd_line6_midi *)((substream)->rmidi->private_data)) | 24 | ((struct snd_line6_midi *)((substream)->rmidi->private_data)) |
25 | 25 | ||
26 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, | 26 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, |
27 | int length); | 27 | int length); |
28 | 28 | ||
29 | /* | 29 | /* |
30 | Pass data received via USB to MIDI. | 30 | Pass data received via USB to MIDI. |
31 | */ | 31 | */ |
32 | void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, | 32 | void line6_midi_receive(struct usb_line6 *line6, unsigned char *data, |
33 | int length) | 33 | int length) |
34 | { | 34 | { |
35 | if (line6->line6midi->substream_receive) | 35 | if (line6->line6midi->substream_receive) |
36 | snd_rawmidi_receive(line6->line6midi->substream_receive, | 36 | snd_rawmidi_receive(line6->line6midi->substream_receive, |
37 | data, length); | 37 | data, length); |
38 | } | 38 | } |
39 | 39 | ||
40 | /* | 40 | /* |
41 | Read data from MIDI buffer and transmit them via USB. | 41 | Read data from MIDI buffer and transmit them via USB. |
42 | */ | 42 | */ |
43 | static void line6_midi_transmit(struct snd_rawmidi_substream *substream) | 43 | static void line6_midi_transmit(struct snd_rawmidi_substream *substream) |
44 | { | 44 | { |
45 | struct usb_line6 *line6 = | 45 | struct usb_line6 *line6 = |
46 | line6_rawmidi_substream_midi(substream)->line6; | 46 | line6_rawmidi_substream_midi(substream)->line6; |
47 | struct snd_line6_midi *line6midi = line6->line6midi; | 47 | struct snd_line6_midi *line6midi = line6->line6midi; |
48 | struct MidiBuffer *mb = &line6midi->midibuf_out; | 48 | struct MidiBuffer *mb = &line6midi->midibuf_out; |
49 | unsigned long flags; | 49 | unsigned long flags; |
50 | unsigned char chunk[line6->max_packet_size]; | 50 | unsigned char chunk[line6->max_packet_size]; |
51 | int req, done; | 51 | int req, done; |
52 | 52 | ||
53 | spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags); | 53 | spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags); |
54 | 54 | ||
55 | for (;;) { | 55 | for (;;) { |
56 | req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); | 56 | req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size); |
57 | done = snd_rawmidi_transmit_peek(substream, chunk, req); | 57 | done = snd_rawmidi_transmit_peek(substream, chunk, req); |
58 | 58 | ||
59 | if (done == 0) | 59 | if (done == 0) |
60 | break; | 60 | break; |
61 | 61 | ||
62 | #ifdef CONFIG_LINE6_USB_DUMP_MIDI | 62 | #ifdef CONFIG_LINE6_USB_DUMP_MIDI |
63 | line6_write_hexdump(line6, 's', chunk, done); | 63 | line6_write_hexdump(line6, 's', chunk, done); |
64 | #endif | 64 | #endif |
65 | line6_midibuf_write(mb, chunk, done); | 65 | line6_midibuf_write(mb, chunk, done); |
66 | snd_rawmidi_transmit_ack(substream, done); | 66 | snd_rawmidi_transmit_ack(substream, done); |
67 | } | 67 | } |
68 | 68 | ||
69 | for (;;) { | 69 | for (;;) { |
70 | done = line6_midibuf_read(mb, chunk, line6->max_packet_size); | 70 | done = line6_midibuf_read(mb, chunk, line6->max_packet_size); |
71 | 71 | ||
72 | if (done == 0) | 72 | if (done == 0) |
73 | break; | 73 | break; |
74 | 74 | ||
75 | if (line6_midibuf_skip_message | 75 | if (line6_midibuf_skip_message |
76 | (mb, line6midi->midi_mask_transmit)) | 76 | (mb, line6midi->midi_mask_transmit)) |
77 | continue; | 77 | continue; |
78 | 78 | ||
79 | send_midi_async(line6, chunk, done); | 79 | send_midi_async(line6, chunk, done); |
80 | } | 80 | } |
81 | 81 | ||
82 | spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); | 82 | spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags); |
83 | } | 83 | } |
84 | 84 | ||
85 | /* | 85 | /* |
86 | Notification of completion of MIDI transmission. | 86 | Notification of completion of MIDI transmission. |
87 | */ | 87 | */ |
88 | static void midi_sent(struct urb *urb) | 88 | static void midi_sent(struct urb *urb) |
89 | { | 89 | { |
90 | unsigned long flags; | 90 | unsigned long flags; |
91 | int status; | 91 | int status; |
92 | int num; | 92 | int num; |
93 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; | 93 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; |
94 | 94 | ||
95 | status = urb->status; | 95 | status = urb->status; |
96 | kfree(urb->transfer_buffer); | 96 | kfree(urb->transfer_buffer); |
97 | usb_free_urb(urb); | 97 | usb_free_urb(urb); |
98 | 98 | ||
99 | if (status == -ESHUTDOWN) | 99 | if (status == -ESHUTDOWN) |
100 | return; | 100 | return; |
101 | 101 | ||
102 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); | 102 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); |
103 | num = --line6->line6midi->num_active_send_urbs; | 103 | num = --line6->line6midi->num_active_send_urbs; |
104 | 104 | ||
105 | if (num == 0) { | 105 | if (num == 0) { |
106 | line6_midi_transmit(line6->line6midi->substream_transmit); | 106 | line6_midi_transmit(line6->line6midi->substream_transmit); |
107 | num = line6->line6midi->num_active_send_urbs; | 107 | num = line6->line6midi->num_active_send_urbs; |
108 | } | 108 | } |
109 | 109 | ||
110 | if (num == 0) | 110 | if (num == 0) |
111 | wake_up(&line6->line6midi->send_wait); | 111 | wake_up(&line6->line6midi->send_wait); |
112 | 112 | ||
113 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); | 113 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); |
114 | } | 114 | } |
115 | 115 | ||
116 | /* | 116 | /* |
117 | Send an asynchronous MIDI message. | 117 | Send an asynchronous MIDI message. |
118 | Assumes that line6->line6midi->send_urb_lock is held | 118 | Assumes that line6->line6midi->send_urb_lock is held |
119 | (i.e., this function is serialized). | 119 | (i.e., this function is serialized). |
120 | */ | 120 | */ |
121 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, | 121 | static int send_midi_async(struct usb_line6 *line6, unsigned char *data, |
122 | int length) | 122 | int length) |
123 | { | 123 | { |
124 | struct urb *urb; | 124 | struct urb *urb; |
125 | int retval; | 125 | int retval; |
126 | unsigned char *transfer_buffer; | 126 | unsigned char *transfer_buffer; |
127 | 127 | ||
128 | urb = usb_alloc_urb(0, GFP_ATOMIC); | 128 | urb = usb_alloc_urb(0, GFP_ATOMIC); |
129 | 129 | ||
130 | if (urb == 0) { | 130 | if (urb == NULL) { |
131 | dev_err(line6->ifcdev, "Out of memory\n"); | 131 | dev_err(line6->ifcdev, "Out of memory\n"); |
132 | return -ENOMEM; | 132 | return -ENOMEM; |
133 | } | 133 | } |
134 | #ifdef CONFIG_LINE6_USB_DUMP_CTRL | 134 | #ifdef CONFIG_LINE6_USB_DUMP_CTRL |
135 | line6_write_hexdump(line6, 'S', data, length); | 135 | line6_write_hexdump(line6, 'S', data, length); |
136 | #endif | 136 | #endif |
137 | 137 | ||
138 | transfer_buffer = kmalloc(length, GFP_ATOMIC); | 138 | transfer_buffer = kmalloc(length, GFP_ATOMIC); |
139 | 139 | ||
140 | if (transfer_buffer == 0) { | 140 | if (transfer_buffer == NULL) { |
141 | usb_free_urb(urb); | 141 | usb_free_urb(urb); |
142 | dev_err(line6->ifcdev, "Out of memory\n"); | 142 | dev_err(line6->ifcdev, "Out of memory\n"); |
143 | return -ENOMEM; | 143 | return -ENOMEM; |
144 | } | 144 | } |
145 | 145 | ||
146 | memcpy(transfer_buffer, data, length); | 146 | memcpy(transfer_buffer, data, length); |
147 | usb_fill_int_urb(urb, line6->usbdev, | 147 | usb_fill_int_urb(urb, line6->usbdev, |
148 | usb_sndbulkpipe(line6->usbdev, | 148 | usb_sndbulkpipe(line6->usbdev, |
149 | line6->ep_control_write), | 149 | line6->ep_control_write), |
150 | transfer_buffer, length, midi_sent, line6, | 150 | transfer_buffer, length, midi_sent, line6, |
151 | line6->interval); | 151 | line6->interval); |
152 | urb->actual_length = 0; | 152 | urb->actual_length = 0; |
153 | retval = usb_submit_urb(urb, GFP_ATOMIC); | 153 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
154 | 154 | ||
155 | if (retval < 0) { | 155 | if (retval < 0) { |
156 | dev_err(line6->ifcdev, "usb_submit_urb failed\n"); | 156 | dev_err(line6->ifcdev, "usb_submit_urb failed\n"); |
157 | usb_free_urb(urb); | 157 | usb_free_urb(urb); |
158 | return -EINVAL; | 158 | return -EINVAL; |
159 | } | 159 | } |
160 | 160 | ||
161 | ++line6->line6midi->num_active_send_urbs; | 161 | ++line6->line6midi->num_active_send_urbs; |
162 | 162 | ||
163 | switch (line6->usbdev->descriptor.idProduct) { | 163 | switch (line6->usbdev->descriptor.idProduct) { |
164 | case LINE6_DEVID_BASSPODXT: | 164 | case LINE6_DEVID_BASSPODXT: |
165 | case LINE6_DEVID_BASSPODXTLIVE: | 165 | case LINE6_DEVID_BASSPODXTLIVE: |
166 | case LINE6_DEVID_BASSPODXTPRO: | 166 | case LINE6_DEVID_BASSPODXTPRO: |
167 | case LINE6_DEVID_PODXT: | 167 | case LINE6_DEVID_PODXT: |
168 | case LINE6_DEVID_PODXTLIVE: | 168 | case LINE6_DEVID_PODXTLIVE: |
169 | case LINE6_DEVID_PODXTPRO: | 169 | case LINE6_DEVID_PODXTPRO: |
170 | case LINE6_DEVID_POCKETPOD: | 170 | case LINE6_DEVID_POCKETPOD: |
171 | line6_pod_midi_postprocess((struct usb_line6_pod *)line6, data, | 171 | line6_pod_midi_postprocess((struct usb_line6_pod *)line6, data, |
172 | length); | 172 | length); |
173 | break; | 173 | break; |
174 | 174 | ||
175 | case LINE6_DEVID_VARIAX: | 175 | case LINE6_DEVID_VARIAX: |
176 | break; | 176 | break; |
177 | 177 | ||
178 | default: | 178 | default: |
179 | MISSING_CASE; | 179 | MISSING_CASE; |
180 | } | 180 | } |
181 | 181 | ||
182 | return 0; | 182 | return 0; |
183 | } | 183 | } |
184 | 184 | ||
185 | static int line6_midi_output_open(struct snd_rawmidi_substream *substream) | 185 | static int line6_midi_output_open(struct snd_rawmidi_substream *substream) |
186 | { | 186 | { |
187 | return 0; | 187 | return 0; |
188 | } | 188 | } |
189 | 189 | ||
190 | static int line6_midi_output_close(struct snd_rawmidi_substream *substream) | 190 | static int line6_midi_output_close(struct snd_rawmidi_substream *substream) |
191 | { | 191 | { |
192 | return 0; | 192 | return 0; |
193 | } | 193 | } |
194 | 194 | ||
195 | static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, | 195 | static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream, |
196 | int up) | 196 | int up) |
197 | { | 197 | { |
198 | unsigned long flags; | 198 | unsigned long flags; |
199 | struct usb_line6 *line6 = | 199 | struct usb_line6 *line6 = |
200 | line6_rawmidi_substream_midi(substream)->line6; | 200 | line6_rawmidi_substream_midi(substream)->line6; |
201 | 201 | ||
202 | line6->line6midi->substream_transmit = substream; | 202 | line6->line6midi->substream_transmit = substream; |
203 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); | 203 | spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags); |
204 | 204 | ||
205 | if (line6->line6midi->num_active_send_urbs == 0) | 205 | if (line6->line6midi->num_active_send_urbs == 0) |
206 | line6_midi_transmit(substream); | 206 | line6_midi_transmit(substream); |
207 | 207 | ||
208 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); | 208 | spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags); |
209 | } | 209 | } |
210 | 210 | ||
211 | static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) | 211 | static void line6_midi_output_drain(struct snd_rawmidi_substream *substream) |
212 | { | 212 | { |
213 | struct usb_line6 *line6 = | 213 | struct usb_line6 *line6 = |
214 | line6_rawmidi_substream_midi(substream)->line6; | 214 | line6_rawmidi_substream_midi(substream)->line6; |
215 | struct snd_line6_midi *midi = line6->line6midi; | 215 | struct snd_line6_midi *midi = line6->line6midi; |
216 | wait_event_interruptible(midi->send_wait, | 216 | wait_event_interruptible(midi->send_wait, |
217 | midi->num_active_send_urbs == 0); | 217 | midi->num_active_send_urbs == 0); |
218 | } | 218 | } |
219 | 219 | ||
220 | static int line6_midi_input_open(struct snd_rawmidi_substream *substream) | 220 | static int line6_midi_input_open(struct snd_rawmidi_substream *substream) |
221 | { | 221 | { |
222 | return 0; | 222 | return 0; |
223 | } | 223 | } |
224 | 224 | ||
225 | static int line6_midi_input_close(struct snd_rawmidi_substream *substream) | 225 | static int line6_midi_input_close(struct snd_rawmidi_substream *substream) |
226 | { | 226 | { |
227 | return 0; | 227 | return 0; |
228 | } | 228 | } |
229 | 229 | ||
230 | static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, | 230 | static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream, |
231 | int up) | 231 | int up) |
232 | { | 232 | { |
233 | struct usb_line6 *line6 = | 233 | struct usb_line6 *line6 = |
234 | line6_rawmidi_substream_midi(substream)->line6; | 234 | line6_rawmidi_substream_midi(substream)->line6; |
235 | 235 | ||
236 | if (up) | 236 | if (up) |
237 | line6->line6midi->substream_receive = substream; | 237 | line6->line6midi->substream_receive = substream; |
238 | else | 238 | else |
239 | line6->line6midi->substream_receive = 0; | 239 | line6->line6midi->substream_receive = 0; |
240 | } | 240 | } |
241 | 241 | ||
242 | static struct snd_rawmidi_ops line6_midi_output_ops = { | 242 | static struct snd_rawmidi_ops line6_midi_output_ops = { |
243 | .open = line6_midi_output_open, | 243 | .open = line6_midi_output_open, |
244 | .close = line6_midi_output_close, | 244 | .close = line6_midi_output_close, |
245 | .trigger = line6_midi_output_trigger, | 245 | .trigger = line6_midi_output_trigger, |
246 | .drain = line6_midi_output_drain, | 246 | .drain = line6_midi_output_drain, |
247 | }; | 247 | }; |
248 | 248 | ||
249 | static struct snd_rawmidi_ops line6_midi_input_ops = { | 249 | static struct snd_rawmidi_ops line6_midi_input_ops = { |
250 | .open = line6_midi_input_open, | 250 | .open = line6_midi_input_open, |
251 | .close = line6_midi_input_close, | 251 | .close = line6_midi_input_close, |
252 | .trigger = line6_midi_input_trigger, | 252 | .trigger = line6_midi_input_trigger, |
253 | }; | 253 | }; |
254 | 254 | ||
255 | /* | 255 | /* |
256 | Cleanup the Line6 MIDI device. | 256 | Cleanup the Line6 MIDI device. |
257 | */ | 257 | */ |
258 | static void line6_cleanup_midi(struct snd_rawmidi *rmidi) | 258 | static void line6_cleanup_midi(struct snd_rawmidi *rmidi) |
259 | { | 259 | { |
260 | } | 260 | } |
261 | 261 | ||
262 | /* Create a MIDI device */ | 262 | /* Create a MIDI device */ |
263 | static int snd_line6_new_midi(struct snd_line6_midi *line6midi) | 263 | static int snd_line6_new_midi(struct snd_line6_midi *line6midi) |
264 | { | 264 | { |
265 | struct snd_rawmidi *rmidi; | 265 | struct snd_rawmidi *rmidi; |
266 | int err; | 266 | int err; |
267 | 267 | ||
268 | err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, | 268 | err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, |
269 | &rmidi); | 269 | &rmidi); |
270 | if (err < 0) | 270 | if (err < 0) |
271 | return err; | 271 | return err; |
272 | 272 | ||
273 | rmidi->private_data = line6midi; | 273 | rmidi->private_data = line6midi; |
274 | rmidi->private_free = line6_cleanup_midi; | 274 | rmidi->private_free = line6_cleanup_midi; |
275 | strcpy(rmidi->id, line6midi->line6->properties->id); | 275 | strcpy(rmidi->id, line6midi->line6->properties->id); |
276 | strcpy(rmidi->name, line6midi->line6->properties->name); | 276 | strcpy(rmidi->name, line6midi->line6->properties->name); |
277 | 277 | ||
278 | rmidi->info_flags = | 278 | rmidi->info_flags = |
279 | SNDRV_RAWMIDI_INFO_OUTPUT | | 279 | SNDRV_RAWMIDI_INFO_OUTPUT | |
280 | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; | 280 | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; |
281 | 281 | ||
282 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | 282 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, |
283 | &line6_midi_output_ops); | 283 | &line6_midi_output_ops); |
284 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | 284 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, |
285 | &line6_midi_input_ops); | 285 | &line6_midi_input_ops); |
286 | return 0; | 286 | return 0; |
287 | } | 287 | } |
288 | 288 | ||
289 | /* | 289 | /* |
290 | "read" request on "midi_mask_transmit" special file. | 290 | "read" request on "midi_mask_transmit" special file. |
291 | */ | 291 | */ |
292 | static ssize_t midi_get_midi_mask_transmit(struct device *dev, | 292 | static ssize_t midi_get_midi_mask_transmit(struct device *dev, |
293 | struct device_attribute *attr, | 293 | struct device_attribute *attr, |
294 | char *buf) | 294 | char *buf) |
295 | { | 295 | { |
296 | struct usb_interface *interface = to_usb_interface(dev); | 296 | struct usb_interface *interface = to_usb_interface(dev); |
297 | struct usb_line6 *line6 = usb_get_intfdata(interface); | 297 | struct usb_line6 *line6 = usb_get_intfdata(interface); |
298 | return sprintf(buf, "%d\n", line6->line6midi->midi_mask_transmit); | 298 | return sprintf(buf, "%d\n", line6->line6midi->midi_mask_transmit); |
299 | } | 299 | } |
300 | 300 | ||
301 | /* | 301 | /* |
302 | "write" request on "midi_mask" special file. | 302 | "write" request on "midi_mask" special file. |
303 | */ | 303 | */ |
304 | static ssize_t midi_set_midi_mask_transmit(struct device *dev, | 304 | static ssize_t midi_set_midi_mask_transmit(struct device *dev, |
305 | struct device_attribute *attr, | 305 | struct device_attribute *attr, |
306 | const char *buf, size_t count) | 306 | const char *buf, size_t count) |
307 | { | 307 | { |
308 | struct usb_interface *interface = to_usb_interface(dev); | 308 | struct usb_interface *interface = to_usb_interface(dev); |
309 | struct usb_line6 *line6 = usb_get_intfdata(interface); | 309 | struct usb_line6 *line6 = usb_get_intfdata(interface); |
310 | unsigned long value; | 310 | unsigned long value; |
311 | int ret; | 311 | int ret; |
312 | 312 | ||
313 | ret = strict_strtoul(buf, 10, &value); | 313 | ret = strict_strtoul(buf, 10, &value); |
314 | if (ret) | 314 | if (ret) |
315 | return ret; | 315 | return ret; |
316 | 316 | ||
317 | line6->line6midi->midi_mask_transmit = value; | 317 | line6->line6midi->midi_mask_transmit = value; |
318 | return count; | 318 | return count; |
319 | } | 319 | } |
320 | 320 | ||
321 | /* | 321 | /* |
322 | "read" request on "midi_mask_receive" special file. | 322 | "read" request on "midi_mask_receive" special file. |
323 | */ | 323 | */ |
324 | static ssize_t midi_get_midi_mask_receive(struct device *dev, | 324 | static ssize_t midi_get_midi_mask_receive(struct device *dev, |
325 | struct device_attribute *attr, | 325 | struct device_attribute *attr, |
326 | char *buf) | 326 | char *buf) |
327 | { | 327 | { |
328 | struct usb_interface *interface = to_usb_interface(dev); | 328 | struct usb_interface *interface = to_usb_interface(dev); |
329 | struct usb_line6 *line6 = usb_get_intfdata(interface); | 329 | struct usb_line6 *line6 = usb_get_intfdata(interface); |
330 | return sprintf(buf, "%d\n", line6->line6midi->midi_mask_receive); | 330 | return sprintf(buf, "%d\n", line6->line6midi->midi_mask_receive); |
331 | } | 331 | } |
332 | 332 | ||
333 | /* | 333 | /* |
334 | "write" request on "midi_mask" special file. | 334 | "write" request on "midi_mask" special file. |
335 | */ | 335 | */ |
336 | static ssize_t midi_set_midi_mask_receive(struct device *dev, | 336 | static ssize_t midi_set_midi_mask_receive(struct device *dev, |
337 | struct device_attribute *attr, | 337 | struct device_attribute *attr, |
338 | const char *buf, size_t count) | 338 | const char *buf, size_t count) |
339 | { | 339 | { |
340 | struct usb_interface *interface = to_usb_interface(dev); | 340 | struct usb_interface *interface = to_usb_interface(dev); |
341 | struct usb_line6 *line6 = usb_get_intfdata(interface); | 341 | struct usb_line6 *line6 = usb_get_intfdata(interface); |
342 | unsigned long value; | 342 | unsigned long value; |
343 | int ret; | 343 | int ret; |
344 | 344 | ||
345 | ret = strict_strtoul(buf, 10, &value); | 345 | ret = strict_strtoul(buf, 10, &value); |
346 | if (ret) | 346 | if (ret) |
347 | return ret; | 347 | return ret; |
348 | 348 | ||
349 | line6->line6midi->midi_mask_receive = value; | 349 | line6->line6midi->midi_mask_receive = value; |
350 | return count; | 350 | return count; |
351 | } | 351 | } |
352 | 352 | ||
353 | static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO, | 353 | static DEVICE_ATTR(midi_mask_transmit, S_IWUSR | S_IRUGO, |
354 | midi_get_midi_mask_transmit, midi_set_midi_mask_transmit); | 354 | midi_get_midi_mask_transmit, midi_set_midi_mask_transmit); |
355 | static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO, | 355 | static DEVICE_ATTR(midi_mask_receive, S_IWUSR | S_IRUGO, |
356 | midi_get_midi_mask_receive, midi_set_midi_mask_receive); | 356 | midi_get_midi_mask_receive, midi_set_midi_mask_receive); |
357 | 357 | ||
358 | /* MIDI device destructor */ | 358 | /* MIDI device destructor */ |
359 | static int snd_line6_midi_free(struct snd_device *device) | 359 | static int snd_line6_midi_free(struct snd_device *device) |
360 | { | 360 | { |
361 | struct snd_line6_midi *line6midi = device->device_data; | 361 | struct snd_line6_midi *line6midi = device->device_data; |
362 | device_remove_file(line6midi->line6->ifcdev, | 362 | device_remove_file(line6midi->line6->ifcdev, |
363 | &dev_attr_midi_mask_transmit); | 363 | &dev_attr_midi_mask_transmit); |
364 | device_remove_file(line6midi->line6->ifcdev, | 364 | device_remove_file(line6midi->line6->ifcdev, |
365 | &dev_attr_midi_mask_receive); | 365 | &dev_attr_midi_mask_receive); |
366 | line6_midibuf_destroy(&line6midi->midibuf_in); | 366 | line6_midibuf_destroy(&line6midi->midibuf_in); |
367 | line6_midibuf_destroy(&line6midi->midibuf_out); | 367 | line6_midibuf_destroy(&line6midi->midibuf_out); |
368 | return 0; | 368 | return 0; |
369 | } | 369 | } |
370 | 370 | ||
371 | /* | 371 | /* |
372 | Initialize the Line6 MIDI subsystem. | 372 | Initialize the Line6 MIDI subsystem. |
373 | */ | 373 | */ |
374 | int line6_init_midi(struct usb_line6 *line6) | 374 | int line6_init_midi(struct usb_line6 *line6) |
375 | { | 375 | { |
376 | static struct snd_device_ops midi_ops = { | 376 | static struct snd_device_ops midi_ops = { |
377 | .dev_free = snd_line6_midi_free, | 377 | .dev_free = snd_line6_midi_free, |
378 | }; | 378 | }; |
379 | 379 | ||
380 | int err; | 380 | int err; |
381 | struct snd_line6_midi *line6midi; | 381 | struct snd_line6_midi *line6midi; |
382 | 382 | ||
383 | if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) { | 383 | if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) { |
384 | /* skip MIDI initialization and report success */ | 384 | /* skip MIDI initialization and report success */ |
385 | return 0; | 385 | return 0; |
386 | } | 386 | } |
387 | 387 | ||
388 | line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); | 388 | line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); |
389 | 389 | ||
390 | if (line6midi == NULL) | 390 | if (line6midi == NULL) |
391 | return -ENOMEM; | 391 | return -ENOMEM; |
392 | 392 | ||
393 | err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); | 393 | err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); |
394 | if (err < 0) | 394 | if (err < 0) |
395 | return err; | 395 | return err; |
396 | 396 | ||
397 | err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); | 397 | err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1); |
398 | if (err < 0) | 398 | if (err < 0) |
399 | return err; | 399 | return err; |
400 | 400 | ||
401 | line6midi->line6 = line6; | 401 | line6midi->line6 = line6; |
402 | line6midi->midi_mask_transmit = 1; | 402 | line6midi->midi_mask_transmit = 1; |
403 | line6midi->midi_mask_receive = 4; | 403 | line6midi->midi_mask_receive = 4; |
404 | line6->line6midi = line6midi; | 404 | line6->line6midi = line6midi; |
405 | 405 | ||
406 | err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, | 406 | err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, |
407 | &midi_ops); | 407 | &midi_ops); |
408 | if (err < 0) | 408 | if (err < 0) |
409 | return err; | 409 | return err; |
410 | 410 | ||
411 | snd_card_set_dev(line6->card, line6->ifcdev); | 411 | snd_card_set_dev(line6->card, line6->ifcdev); |
412 | 412 | ||
413 | err = snd_line6_new_midi(line6midi); | 413 | err = snd_line6_new_midi(line6midi); |
414 | if (err < 0) | 414 | if (err < 0) |
415 | return err; | 415 | return err; |
416 | 416 | ||
417 | err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_transmit); | 417 | err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_transmit); |
418 | if (err < 0) | 418 | if (err < 0) |
419 | return err; | 419 | return err; |
420 | 420 | ||
421 | err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_receive); | 421 | err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_receive); |
422 | if (err < 0) | 422 | if (err < 0) |
423 | return err; | 423 | return err; |
424 | 424 | ||
425 | init_waitqueue_head(&line6midi->send_wait); | 425 | init_waitqueue_head(&line6midi->send_wait); |
426 | spin_lock_init(&line6midi->send_urb_lock); | 426 | spin_lock_init(&line6midi->send_urb_lock); |
427 | spin_lock_init(&line6midi->midi_transmit_lock); | 427 | spin_lock_init(&line6midi->midi_transmit_lock); |
428 | return 0; | 428 | return 0; |
429 | } | 429 | } |
430 | 430 |
drivers/staging/line6/playback.c
1 | /* | 1 | /* |
2 | * Line6 Linux USB driver - 0.9.1beta | 2 | * Line6 Linux USB driver - 0.9.1beta |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 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 | 7 | * modify it under the terms of the GNU General Public License as |
8 | * published by the Free Software Foundation, version 2. | 8 | * published by the Free Software Foundation, version 2. |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <sound/core.h> | 12 | #include <sound/core.h> |
13 | #include <sound/pcm.h> | 13 | #include <sound/pcm.h> |
14 | #include <sound/pcm_params.h> | 14 | #include <sound/pcm_params.h> |
15 | 15 | ||
16 | #include "audio.h" | 16 | #include "audio.h" |
17 | #include "capture.h" | 17 | #include "capture.h" |
18 | #include "driver.h" | 18 | #include "driver.h" |
19 | #include "pcm.h" | 19 | #include "pcm.h" |
20 | #include "pod.h" | 20 | #include "pod.h" |
21 | #include "playback.h" | 21 | #include "playback.h" |
22 | 22 | ||
23 | /* | 23 | /* |
24 | Software stereo volume control. | 24 | Software stereo volume control. |
25 | */ | 25 | */ |
26 | static void change_volume(struct urb *urb_out, int volume[], | 26 | static void change_volume(struct urb *urb_out, int volume[], |
27 | int bytes_per_frame) | 27 | int bytes_per_frame) |
28 | { | 28 | { |
29 | int chn = 0; | 29 | int chn = 0; |
30 | 30 | ||
31 | if (volume[0] == 256 && volume[1] == 256) | 31 | if (volume[0] == 256 && volume[1] == 256) |
32 | return; /* maximum volume - no change */ | 32 | return; /* maximum volume - no change */ |
33 | 33 | ||
34 | if (bytes_per_frame == 4) { | 34 | if (bytes_per_frame == 4) { |
35 | short *p, *buf_end; | 35 | short *p, *buf_end; |
36 | p = (short *)urb_out->transfer_buffer; | 36 | p = (short *)urb_out->transfer_buffer; |
37 | buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); | 37 | buf_end = p + urb_out->transfer_buffer_length / sizeof(*p); |
38 | 38 | ||
39 | for (; p < buf_end; ++p) { | 39 | for (; p < buf_end; ++p) { |
40 | *p = (*p * volume[chn & 1]) >> 8; | 40 | *p = (*p * volume[chn & 1]) >> 8; |
41 | ++chn; | 41 | ++chn; |
42 | } | 42 | } |
43 | } else if (bytes_per_frame == 6) { | 43 | } else if (bytes_per_frame == 6) { |
44 | unsigned char *p, *buf_end; | 44 | unsigned char *p, *buf_end; |
45 | p = (unsigned char *)urb_out->transfer_buffer; | 45 | p = (unsigned char *)urb_out->transfer_buffer; |
46 | buf_end = p + urb_out->transfer_buffer_length; | 46 | buf_end = p + urb_out->transfer_buffer_length; |
47 | 47 | ||
48 | for (; p < buf_end; p += 3) { | 48 | for (; p < buf_end; p += 3) { |
49 | int val; | 49 | int val; |
50 | val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); | 50 | val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16); |
51 | val = (val * volume[chn & 1]) >> 8; | 51 | val = (val * volume[chn & 1]) >> 8; |
52 | p[0] = val; | 52 | p[0] = val; |
53 | p[1] = val >> 8; | 53 | p[1] = val >> 8; |
54 | p[2] = val >> 16; | 54 | p[2] = val >> 16; |
55 | ++chn; | 55 | ++chn; |
56 | } | 56 | } |
57 | } | 57 | } |
58 | } | 58 | } |
59 | 59 | ||
60 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | 60 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
61 | 61 | ||
62 | /* | 62 | /* |
63 | Create signal for impulse response test. | 63 | Create signal for impulse response test. |
64 | */ | 64 | */ |
65 | static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, | 65 | static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, |
66 | struct urb *urb_out, int bytes_per_frame) | 66 | struct urb *urb_out, int bytes_per_frame) |
67 | { | 67 | { |
68 | int frames = urb_out->transfer_buffer_length / bytes_per_frame; | 68 | int frames = urb_out->transfer_buffer_length / bytes_per_frame; |
69 | 69 | ||
70 | if (bytes_per_frame == 4) { | 70 | if (bytes_per_frame == 4) { |
71 | int i; | 71 | int i; |
72 | short *pi = (short *)line6pcm->prev_fbuf; | 72 | short *pi = (short *)line6pcm->prev_fbuf; |
73 | short *po = (short *)urb_out->transfer_buffer; | 73 | short *po = (short *)urb_out->transfer_buffer; |
74 | 74 | ||
75 | for (i = 0; i < frames; ++i) { | 75 | for (i = 0; i < frames; ++i) { |
76 | po[0] = pi[0]; | 76 | po[0] = pi[0]; |
77 | po[1] = 0; | 77 | po[1] = 0; |
78 | pi += 2; | 78 | pi += 2; |
79 | po += 2; | 79 | po += 2; |
80 | } | 80 | } |
81 | } else if (bytes_per_frame == 6) { | 81 | } else if (bytes_per_frame == 6) { |
82 | int i, j; | 82 | int i, j; |
83 | unsigned char *pi = line6pcm->prev_fbuf; | 83 | unsigned char *pi = line6pcm->prev_fbuf; |
84 | unsigned char *po = urb_out->transfer_buffer; | 84 | unsigned char *po = urb_out->transfer_buffer; |
85 | 85 | ||
86 | for (i = 0; i < frames; ++i) { | 86 | for (i = 0; i < frames; ++i) { |
87 | for (j = 0; j < bytes_per_frame / 2; ++j) | 87 | for (j = 0; j < bytes_per_frame / 2; ++j) |
88 | po[j] = pi[j]; | 88 | po[j] = pi[j]; |
89 | 89 | ||
90 | for (; j < bytes_per_frame; ++j) | 90 | for (; j < bytes_per_frame; ++j) |
91 | po[j] = 0; | 91 | po[j] = 0; |
92 | 92 | ||
93 | pi += bytes_per_frame; | 93 | pi += bytes_per_frame; |
94 | po += bytes_per_frame; | 94 | po += bytes_per_frame; |
95 | } | 95 | } |
96 | } | 96 | } |
97 | if (--line6pcm->impulse_count <= 0) { | 97 | if (--line6pcm->impulse_count <= 0) { |
98 | ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame - | 98 | ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame - |
99 | 1] = | 99 | 1] = |
100 | line6pcm->impulse_volume; | 100 | line6pcm->impulse_volume; |
101 | line6pcm->impulse_count = line6pcm->impulse_period; | 101 | line6pcm->impulse_count = line6pcm->impulse_period; |
102 | } | 102 | } |
103 | } | 103 | } |
104 | 104 | ||
105 | #endif | 105 | #endif |
106 | 106 | ||
107 | /* | 107 | /* |
108 | Add signal to buffer for software monitoring. | 108 | Add signal to buffer for software monitoring. |
109 | */ | 109 | */ |
110 | static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, | 110 | static void add_monitor_signal(struct urb *urb_out, unsigned char *signal, |
111 | int volume, int bytes_per_frame) | 111 | int volume, int bytes_per_frame) |
112 | { | 112 | { |
113 | if (volume == 0) | 113 | if (volume == 0) |
114 | return; /* zero volume - no change */ | 114 | return; /* zero volume - no change */ |
115 | 115 | ||
116 | if (bytes_per_frame == 4) { | 116 | if (bytes_per_frame == 4) { |
117 | short *pi, *po, *buf_end; | 117 | short *pi, *po, *buf_end; |
118 | pi = (short *)signal; | 118 | pi = (short *)signal; |
119 | po = (short *)urb_out->transfer_buffer; | 119 | po = (short *)urb_out->transfer_buffer; |
120 | buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); | 120 | buf_end = po + urb_out->transfer_buffer_length / sizeof(*po); |
121 | 121 | ||
122 | for (; po < buf_end; ++pi, ++po) | 122 | for (; po < buf_end; ++pi, ++po) |
123 | *po += (*pi * volume) >> 8; | 123 | *po += (*pi * volume) >> 8; |
124 | } | 124 | } |
125 | 125 | ||
126 | /* | 126 | /* |
127 | We don't need to handle devices with 6 bytes per frame here | 127 | We don't need to handle devices with 6 bytes per frame here |
128 | since they all support hardware monitoring. | 128 | since they all support hardware monitoring. |
129 | */ | 129 | */ |
130 | } | 130 | } |
131 | 131 | ||
132 | /* | 132 | /* |
133 | Find a free URB, prepare audio data, and submit URB. | 133 | Find a free URB, prepare audio data, and submit URB. |
134 | */ | 134 | */ |
135 | static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) | 135 | static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) |
136 | { | 136 | { |
137 | int index; | 137 | int index; |
138 | unsigned long flags; | 138 | unsigned long flags; |
139 | int i, urb_size, urb_frames; | 139 | int i, urb_size, urb_frames; |
140 | int ret; | 140 | int ret; |
141 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; | 141 | const int bytes_per_frame = line6pcm->properties->bytes_per_frame; |
142 | const int frame_increment = | 142 | const int frame_increment = |
143 | line6pcm->properties->snd_line6_rates.rats[0].num_min; | 143 | line6pcm->properties->snd_line6_rates.rats[0].num_min; |
144 | const int frame_factor = | 144 | const int frame_factor = |
145 | line6pcm->properties->snd_line6_rates.rats[0].den * | 145 | line6pcm->properties->snd_line6_rates.rats[0].den * |
146 | (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); | 146 | (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL); |
147 | struct urb *urb_out; | 147 | struct urb *urb_out; |
148 | 148 | ||
149 | spin_lock_irqsave(&line6pcm->lock_audio_out, flags); | 149 | spin_lock_irqsave(&line6pcm->lock_audio_out, flags); |
150 | index = | 150 | index = |
151 | find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS); | 151 | find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS); |
152 | 152 | ||
153 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { | 153 | if (index < 0 || index >= LINE6_ISO_BUFFERS) { |
154 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | 154 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); |
155 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); | 155 | dev_err(line6pcm->line6->ifcdev, "no free URB found\n"); |
156 | return -EINVAL; | 156 | return -EINVAL; |
157 | } | 157 | } |
158 | 158 | ||
159 | urb_out = line6pcm->urb_audio_out[index]; | 159 | urb_out = line6pcm->urb_audio_out[index]; |
160 | urb_size = 0; | 160 | urb_size = 0; |
161 | 161 | ||
162 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | 162 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { |
163 | /* compute frame size for given sampling rate */ | 163 | /* compute frame size for given sampling rate */ |
164 | int fsize = 0; | 164 | int fsize = 0; |
165 | struct usb_iso_packet_descriptor *fout = | 165 | struct usb_iso_packet_descriptor *fout = |
166 | &urb_out->iso_frame_desc[i]; | 166 | &urb_out->iso_frame_desc[i]; |
167 | 167 | ||
168 | if (line6pcm->flags & MASK_CAPTURE) | 168 | if (line6pcm->flags & MASK_CAPTURE) |
169 | fsize = line6pcm->prev_fsize; | 169 | fsize = line6pcm->prev_fsize; |
170 | 170 | ||
171 | if (fsize == 0) { | 171 | if (fsize == 0) { |
172 | int n; | 172 | int n; |
173 | line6pcm->count_out += frame_increment; | 173 | line6pcm->count_out += frame_increment; |
174 | n = line6pcm->count_out / frame_factor; | 174 | n = line6pcm->count_out / frame_factor; |
175 | line6pcm->count_out -= n * frame_factor; | 175 | line6pcm->count_out -= n * frame_factor; |
176 | fsize = n * bytes_per_frame; | 176 | fsize = n * bytes_per_frame; |
177 | } | 177 | } |
178 | 178 | ||
179 | fout->offset = urb_size; | 179 | fout->offset = urb_size; |
180 | fout->length = fsize; | 180 | fout->length = fsize; |
181 | urb_size += fsize; | 181 | urb_size += fsize; |
182 | } | 182 | } |
183 | 183 | ||
184 | if (urb_size == 0) { | 184 | if (urb_size == 0) { |
185 | /* can't determine URB size */ | 185 | /* can't determine URB size */ |
186 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | 186 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); |
187 | dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); /* this is somewhat paranoid */ | 187 | dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n"); /* this is somewhat paranoid */ |
188 | return -EINVAL; | 188 | return -EINVAL; |
189 | } | 189 | } |
190 | 190 | ||
191 | urb_frames = urb_size / bytes_per_frame; | 191 | urb_frames = urb_size / bytes_per_frame; |
192 | urb_out->transfer_buffer = | 192 | urb_out->transfer_buffer = |
193 | line6pcm->buffer_out + | 193 | line6pcm->buffer_out + |
194 | line6pcm->max_packet_size * line6pcm->index_out; | 194 | line6pcm->max_packet_size * line6pcm->index_out; |
195 | urb_out->transfer_buffer_length = urb_size; | 195 | urb_out->transfer_buffer_length = urb_size; |
196 | urb_out->context = line6pcm; | 196 | urb_out->context = line6pcm; |
197 | 197 | ||
198 | if (++line6pcm->index_out == LINE6_ISO_BUFFERS) | 198 | if (++line6pcm->index_out == LINE6_ISO_BUFFERS) |
199 | line6pcm->index_out = 0; | 199 | line6pcm->index_out = 0; |
200 | 200 | ||
201 | if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) && | 201 | if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) && |
202 | !test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) { | 202 | !test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) { |
203 | struct snd_pcm_runtime *runtime = | 203 | struct snd_pcm_runtime *runtime = |
204 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; | 204 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime; |
205 | 205 | ||
206 | if (line6pcm->pos_out + urb_frames > runtime->buffer_size) { | 206 | if (line6pcm->pos_out + urb_frames > runtime->buffer_size) { |
207 | /* | 207 | /* |
208 | The transferred area goes over buffer boundary, | 208 | The transferred area goes over buffer boundary, |
209 | copy the data to the temp buffer. | 209 | copy the data to the temp buffer. |
210 | */ | 210 | */ |
211 | int len; | 211 | int len; |
212 | len = runtime->buffer_size - line6pcm->pos_out; | 212 | len = runtime->buffer_size - line6pcm->pos_out; |
213 | 213 | ||
214 | if (len > 0) { | 214 | if (len > 0) { |
215 | memcpy(urb_out->transfer_buffer, | 215 | memcpy(urb_out->transfer_buffer, |
216 | runtime->dma_area + | 216 | runtime->dma_area + |
217 | line6pcm->pos_out * bytes_per_frame, | 217 | line6pcm->pos_out * bytes_per_frame, |
218 | len * bytes_per_frame); | 218 | len * bytes_per_frame); |
219 | memcpy(urb_out->transfer_buffer + | 219 | memcpy(urb_out->transfer_buffer + |
220 | len * bytes_per_frame, runtime->dma_area, | 220 | len * bytes_per_frame, runtime->dma_area, |
221 | (urb_frames - len) * bytes_per_frame); | 221 | (urb_frames - len) * bytes_per_frame); |
222 | } else | 222 | } else |
223 | dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", len); /* this is somewhat paranoid */ | 223 | dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n", len); /* this is somewhat paranoid */ |
224 | } else { | 224 | } else { |
225 | #if LINE6_REUSE_DMA_AREA_FOR_PLAYBACK | 225 | #if LINE6_REUSE_DMA_AREA_FOR_PLAYBACK |
226 | /* set the buffer pointer */ | 226 | /* set the buffer pointer */ |
227 | urb_out->transfer_buffer = | 227 | urb_out->transfer_buffer = |
228 | runtime->dma_area + | 228 | runtime->dma_area + |
229 | line6pcm->pos_out * bytes_per_frame; | 229 | line6pcm->pos_out * bytes_per_frame; |
230 | #else | 230 | #else |
231 | /* copy data */ | 231 | /* copy data */ |
232 | memcpy(urb_out->transfer_buffer, | 232 | memcpy(urb_out->transfer_buffer, |
233 | runtime->dma_area + | 233 | runtime->dma_area + |
234 | line6pcm->pos_out * bytes_per_frame, | 234 | line6pcm->pos_out * bytes_per_frame, |
235 | urb_out->transfer_buffer_length); | 235 | urb_out->transfer_buffer_length); |
236 | #endif | 236 | #endif |
237 | } | 237 | } |
238 | 238 | ||
239 | line6pcm->pos_out += urb_frames; | 239 | line6pcm->pos_out += urb_frames; |
240 | if (line6pcm->pos_out >= runtime->buffer_size) | 240 | if (line6pcm->pos_out >= runtime->buffer_size) |
241 | line6pcm->pos_out -= runtime->buffer_size; | 241 | line6pcm->pos_out -= runtime->buffer_size; |
242 | } else { | 242 | } else { |
243 | memset(urb_out->transfer_buffer, 0, | 243 | memset(urb_out->transfer_buffer, 0, |
244 | urb_out->transfer_buffer_length); | 244 | urb_out->transfer_buffer_length); |
245 | } | 245 | } |
246 | 246 | ||
247 | change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); | 247 | change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); |
248 | 248 | ||
249 | if (line6pcm->prev_fbuf != 0) { | 249 | if (line6pcm->prev_fbuf != NULL) { |
250 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | 250 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
251 | if (line6pcm->flags & MASK_PCM_IMPULSE) { | 251 | if (line6pcm->flags & MASK_PCM_IMPULSE) { |
252 | create_impulse_test_signal(line6pcm, urb_out, | 252 | create_impulse_test_signal(line6pcm, urb_out, |
253 | bytes_per_frame); | 253 | bytes_per_frame); |
254 | if (line6pcm->flags & MASK_PCM_ALSA_CAPTURE) { | 254 | if (line6pcm->flags & MASK_PCM_ALSA_CAPTURE) { |
255 | line6_capture_copy(line6pcm, | 255 | line6_capture_copy(line6pcm, |
256 | urb_out->transfer_buffer, | 256 | urb_out->transfer_buffer, |
257 | urb_out-> | 257 | urb_out-> |
258 | transfer_buffer_length); | 258 | transfer_buffer_length); |
259 | line6_capture_check_period(line6pcm, | 259 | line6_capture_check_period(line6pcm, |
260 | urb_out->transfer_buffer_length); | 260 | urb_out->transfer_buffer_length); |
261 | } | 261 | } |
262 | } else { | 262 | } else { |
263 | #endif | 263 | #endif |
264 | if (! | 264 | if (! |
265 | (line6pcm->line6-> | 265 | (line6pcm->line6-> |
266 | properties->capabilities & LINE6_BIT_HWMON) | 266 | properties->capabilities & LINE6_BIT_HWMON) |
267 | && (line6pcm->flags & MASK_PLAYBACK) | 267 | && (line6pcm->flags & MASK_PLAYBACK) |
268 | && (line6pcm->flags & MASK_CAPTURE)) | 268 | && (line6pcm->flags & MASK_CAPTURE)) |
269 | add_monitor_signal(urb_out, line6pcm->prev_fbuf, | 269 | add_monitor_signal(urb_out, line6pcm->prev_fbuf, |
270 | line6pcm->volume_monitor, | 270 | line6pcm->volume_monitor, |
271 | bytes_per_frame); | 271 | bytes_per_frame); |
272 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE | 272 | #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE |
273 | } | 273 | } |
274 | #endif | 274 | #endif |
275 | } | 275 | } |
276 | #ifdef CONFIG_LINE6_USB_DUMP_PCM | 276 | #ifdef CONFIG_LINE6_USB_DUMP_PCM |
277 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { | 277 | for (i = 0; i < LINE6_ISO_PACKETS; ++i) { |
278 | struct usb_iso_packet_descriptor *fout = | 278 | struct usb_iso_packet_descriptor *fout = |
279 | &urb_out->iso_frame_desc[i]; | 279 | &urb_out->iso_frame_desc[i]; |
280 | line6_write_hexdump(line6pcm->line6, 'P', | 280 | line6_write_hexdump(line6pcm->line6, 'P', |
281 | urb_out->transfer_buffer + fout->offset, | 281 | urb_out->transfer_buffer + fout->offset, |
282 | fout->length); | 282 | fout->length); |
283 | } | 283 | } |
284 | #endif | 284 | #endif |
285 | 285 | ||
286 | ret = usb_submit_urb(urb_out, GFP_ATOMIC); | 286 | ret = usb_submit_urb(urb_out, GFP_ATOMIC); |
287 | 287 | ||
288 | if (ret == 0) | 288 | if (ret == 0) |
289 | set_bit(index, &line6pcm->active_urb_out); | 289 | set_bit(index, &line6pcm->active_urb_out); |
290 | else | 290 | else |
291 | dev_err(line6pcm->line6->ifcdev, | 291 | dev_err(line6pcm->line6->ifcdev, |
292 | "URB out #%d submission failed (%d)\n", index, ret); | 292 | "URB out #%d submission failed (%d)\n", index, ret); |
293 | 293 | ||
294 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | 294 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); |
295 | return 0; | 295 | return 0; |
296 | } | 296 | } |
297 | 297 | ||
298 | /* | 298 | /* |
299 | Submit all currently available playback URBs. | 299 | Submit all currently available playback URBs. |
300 | */ | 300 | */ |
301 | int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) | 301 | int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm) |
302 | { | 302 | { |
303 | int ret, i; | 303 | int ret, i; |
304 | 304 | ||
305 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | 305 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { |
306 | ret = submit_audio_out_urb(line6pcm); | 306 | ret = submit_audio_out_urb(line6pcm); |
307 | if (ret < 0) | 307 | if (ret < 0) |
308 | return ret; | 308 | return ret; |
309 | } | 309 | } |
310 | 310 | ||
311 | return 0; | 311 | return 0; |
312 | } | 312 | } |
313 | 313 | ||
314 | /* | 314 | /* |
315 | Unlink all currently active playback URBs. | 315 | Unlink all currently active playback URBs. |
316 | */ | 316 | */ |
317 | void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) | 317 | void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm) |
318 | { | 318 | { |
319 | unsigned int i; | 319 | unsigned int i; |
320 | 320 | ||
321 | for (i = LINE6_ISO_BUFFERS; i--;) { | 321 | for (i = LINE6_ISO_BUFFERS; i--;) { |
322 | if (test_bit(i, &line6pcm->active_urb_out)) { | 322 | if (test_bit(i, &line6pcm->active_urb_out)) { |
323 | if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { | 323 | if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) { |
324 | struct urb *u = line6pcm->urb_audio_out[i]; | 324 | struct urb *u = line6pcm->urb_audio_out[i]; |
325 | usb_unlink_urb(u); | 325 | usb_unlink_urb(u); |
326 | } | 326 | } |
327 | } | 327 | } |
328 | } | 328 | } |
329 | } | 329 | } |
330 | 330 | ||
331 | /* | 331 | /* |
332 | Wait until unlinking of all currently active playback URBs has been finished. | 332 | Wait until unlinking of all currently active playback URBs has been finished. |
333 | */ | 333 | */ |
334 | static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) | 334 | static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) |
335 | { | 335 | { |
336 | int timeout = HZ; | 336 | int timeout = HZ; |
337 | unsigned int i; | 337 | unsigned int i; |
338 | int alive; | 338 | int alive; |
339 | 339 | ||
340 | do { | 340 | do { |
341 | alive = 0; | 341 | alive = 0; |
342 | for (i = LINE6_ISO_BUFFERS; i--;) { | 342 | for (i = LINE6_ISO_BUFFERS; i--;) { |
343 | if (test_bit(i, &line6pcm->active_urb_out)) | 343 | if (test_bit(i, &line6pcm->active_urb_out)) |
344 | alive++; | 344 | alive++; |
345 | } | 345 | } |
346 | if (!alive) | 346 | if (!alive) |
347 | break; | 347 | break; |
348 | set_current_state(TASK_UNINTERRUPTIBLE); | 348 | set_current_state(TASK_UNINTERRUPTIBLE); |
349 | schedule_timeout(1); | 349 | schedule_timeout(1); |
350 | } while (--timeout > 0); | 350 | } while (--timeout > 0); |
351 | if (alive) | 351 | if (alive) |
352 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); | 352 | snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); |
353 | } | 353 | } |
354 | 354 | ||
355 | /* | 355 | /* |
356 | Unlink all currently active playback URBs, and wait for finishing. | 356 | Unlink all currently active playback URBs, and wait for finishing. |
357 | */ | 357 | */ |
358 | void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) | 358 | void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm) |
359 | { | 359 | { |
360 | line6_unlink_audio_out_urbs(line6pcm); | 360 | line6_unlink_audio_out_urbs(line6pcm); |
361 | wait_clear_audio_out_urbs(line6pcm); | 361 | wait_clear_audio_out_urbs(line6pcm); |
362 | } | 362 | } |
363 | 363 | ||
364 | /* | 364 | /* |
365 | Callback for completed playback URB. | 365 | Callback for completed playback URB. |
366 | */ | 366 | */ |
367 | static void audio_out_callback(struct urb *urb) | 367 | static void audio_out_callback(struct urb *urb) |
368 | { | 368 | { |
369 | int i, index, length = 0, shutdown = 0; | 369 | int i, index, length = 0, shutdown = 0; |
370 | unsigned long flags; | 370 | unsigned long flags; |
371 | 371 | ||
372 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; | 372 | struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context; |
373 | struct snd_pcm_substream *substream = | 373 | struct snd_pcm_substream *substream = |
374 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); | 374 | get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK); |
375 | 375 | ||
376 | #if USE_CLEAR_BUFFER_WORKAROUND | 376 | #if USE_CLEAR_BUFFER_WORKAROUND |
377 | memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); | 377 | memset(urb->transfer_buffer, 0, urb->transfer_buffer_length); |
378 | #endif | 378 | #endif |
379 | 379 | ||
380 | line6pcm->last_frame_out = urb->start_frame; | 380 | line6pcm->last_frame_out = urb->start_frame; |
381 | 381 | ||
382 | /* find index of URB */ | 382 | /* find index of URB */ |
383 | for (index = LINE6_ISO_BUFFERS; index--;) | 383 | for (index = LINE6_ISO_BUFFERS; index--;) |
384 | if (urb == line6pcm->urb_audio_out[index]) | 384 | if (urb == line6pcm->urb_audio_out[index]) |
385 | break; | 385 | break; |
386 | 386 | ||
387 | if (index < 0) | 387 | if (index < 0) |
388 | return; /* URB has been unlinked asynchronously */ | 388 | return; /* URB has been unlinked asynchronously */ |
389 | 389 | ||
390 | for (i = LINE6_ISO_PACKETS; i--;) | 390 | for (i = LINE6_ISO_PACKETS; i--;) |
391 | length += urb->iso_frame_desc[i].length; | 391 | length += urb->iso_frame_desc[i].length; |
392 | 392 | ||
393 | spin_lock_irqsave(&line6pcm->lock_audio_out, flags); | 393 | spin_lock_irqsave(&line6pcm->lock_audio_out, flags); |
394 | 394 | ||
395 | if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) { | 395 | if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) { |
396 | struct snd_pcm_runtime *runtime = substream->runtime; | 396 | struct snd_pcm_runtime *runtime = substream->runtime; |
397 | line6pcm->pos_out_done += | 397 | line6pcm->pos_out_done += |
398 | length / line6pcm->properties->bytes_per_frame; | 398 | length / line6pcm->properties->bytes_per_frame; |
399 | 399 | ||
400 | if (line6pcm->pos_out_done >= runtime->buffer_size) | 400 | if (line6pcm->pos_out_done >= runtime->buffer_size) |
401 | line6pcm->pos_out_done -= runtime->buffer_size; | 401 | line6pcm->pos_out_done -= runtime->buffer_size; |
402 | } | 402 | } |
403 | 403 | ||
404 | clear_bit(index, &line6pcm->active_urb_out); | 404 | clear_bit(index, &line6pcm->active_urb_out); |
405 | 405 | ||
406 | for (i = LINE6_ISO_PACKETS; i--;) | 406 | for (i = LINE6_ISO_PACKETS; i--;) |
407 | if (urb->iso_frame_desc[i].status == -EXDEV) { | 407 | if (urb->iso_frame_desc[i].status == -EXDEV) { |
408 | shutdown = 1; | 408 | shutdown = 1; |
409 | break; | 409 | break; |
410 | } | 410 | } |
411 | 411 | ||
412 | if (test_and_clear_bit(index, &line6pcm->unlink_urb_out)) | 412 | if (test_and_clear_bit(index, &line6pcm->unlink_urb_out)) |
413 | shutdown = 1; | 413 | shutdown = 1; |
414 | 414 | ||
415 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); | 415 | spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags); |
416 | 416 | ||
417 | if (!shutdown) { | 417 | if (!shutdown) { |
418 | submit_audio_out_urb(line6pcm); | 418 | submit_audio_out_urb(line6pcm); |
419 | 419 | ||
420 | if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) { | 420 | if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) { |
421 | line6pcm->bytes_out += length; | 421 | line6pcm->bytes_out += length; |
422 | if (line6pcm->bytes_out >= line6pcm->period_out) { | 422 | if (line6pcm->bytes_out >= line6pcm->period_out) { |
423 | line6pcm->bytes_out %= line6pcm->period_out; | 423 | line6pcm->bytes_out %= line6pcm->period_out; |
424 | snd_pcm_period_elapsed(substream); | 424 | snd_pcm_period_elapsed(substream); |
425 | } | 425 | } |
426 | } | 426 | } |
427 | } | 427 | } |
428 | } | 428 | } |
429 | 429 | ||
430 | /* open playback callback */ | 430 | /* open playback callback */ |
431 | static int snd_line6_playback_open(struct snd_pcm_substream *substream) | 431 | static int snd_line6_playback_open(struct snd_pcm_substream *substream) |
432 | { | 432 | { |
433 | int err; | 433 | int err; |
434 | struct snd_pcm_runtime *runtime = substream->runtime; | 434 | struct snd_pcm_runtime *runtime = substream->runtime; |
435 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 435 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
436 | 436 | ||
437 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 437 | err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
438 | (&line6pcm-> | 438 | (&line6pcm-> |
439 | properties->snd_line6_rates)); | 439 | properties->snd_line6_rates)); |
440 | if (err < 0) | 440 | if (err < 0) |
441 | return err; | 441 | return err; |
442 | 442 | ||
443 | runtime->hw = line6pcm->properties->snd_line6_playback_hw; | 443 | runtime->hw = line6pcm->properties->snd_line6_playback_hw; |
444 | return 0; | 444 | return 0; |
445 | } | 445 | } |
446 | 446 | ||
447 | /* close playback callback */ | 447 | /* close playback callback */ |
448 | static int snd_line6_playback_close(struct snd_pcm_substream *substream) | 448 | static int snd_line6_playback_close(struct snd_pcm_substream *substream) |
449 | { | 449 | { |
450 | return 0; | 450 | return 0; |
451 | } | 451 | } |
452 | 452 | ||
453 | /* hw_params playback callback */ | 453 | /* hw_params playback callback */ |
454 | static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, | 454 | static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, |
455 | struct snd_pcm_hw_params *hw_params) | 455 | struct snd_pcm_hw_params *hw_params) |
456 | { | 456 | { |
457 | int ret; | 457 | int ret; |
458 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 458 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
459 | 459 | ||
460 | /* -- Florian Demski [FD] */ | 460 | /* -- Florian Demski [FD] */ |
461 | /* don't ask me why, but this fixes the bug on my machine */ | 461 | /* don't ask me why, but this fixes the bug on my machine */ |
462 | if (line6pcm == NULL) { | 462 | if (line6pcm == NULL) { |
463 | if (substream->pcm == NULL) | 463 | if (substream->pcm == NULL) |
464 | return -ENOMEM; | 464 | return -ENOMEM; |
465 | if (substream->pcm->private_data == NULL) | 465 | if (substream->pcm->private_data == NULL) |
466 | return -ENOMEM; | 466 | return -ENOMEM; |
467 | substream->private_data = substream->pcm->private_data; | 467 | substream->private_data = substream->pcm->private_data; |
468 | line6pcm = snd_pcm_substream_chip(substream); | 468 | line6pcm = snd_pcm_substream_chip(substream); |
469 | } | 469 | } |
470 | /* -- [FD] end */ | 470 | /* -- [FD] end */ |
471 | 471 | ||
472 | ret = snd_pcm_lib_malloc_pages(substream, | 472 | ret = snd_pcm_lib_malloc_pages(substream, |
473 | params_buffer_bytes(hw_params)); | 473 | params_buffer_bytes(hw_params)); |
474 | if (ret < 0) | 474 | if (ret < 0) |
475 | return ret; | 475 | return ret; |
476 | 476 | ||
477 | line6pcm->period_out = params_period_bytes(hw_params); | 477 | line6pcm->period_out = params_period_bytes(hw_params); |
478 | return 0; | 478 | return 0; |
479 | } | 479 | } |
480 | 480 | ||
481 | /* hw_free playback callback */ | 481 | /* hw_free playback callback */ |
482 | static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) | 482 | static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream) |
483 | { | 483 | { |
484 | return snd_pcm_lib_free_pages(substream); | 484 | return snd_pcm_lib_free_pages(substream); |
485 | } | 485 | } |
486 | 486 | ||
487 | /* trigger playback callback */ | 487 | /* trigger playback callback */ |
488 | int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) | 488 | int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) |
489 | { | 489 | { |
490 | int err; | 490 | int err; |
491 | 491 | ||
492 | switch (cmd) { | 492 | switch (cmd) { |
493 | case SNDRV_PCM_TRIGGER_START: | 493 | case SNDRV_PCM_TRIGGER_START: |
494 | #ifdef CONFIG_PM | 494 | #ifdef CONFIG_PM |
495 | case SNDRV_PCM_TRIGGER_RESUME: | 495 | case SNDRV_PCM_TRIGGER_RESUME: |
496 | #endif | 496 | #endif |
497 | err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_PLAYBACK); | 497 | err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_PLAYBACK); |
498 | 498 | ||
499 | if (err < 0) | 499 | if (err < 0) |
500 | return err; | 500 | return err; |
501 | 501 | ||
502 | break; | 502 | break; |
503 | 503 | ||
504 | case SNDRV_PCM_TRIGGER_STOP: | 504 | case SNDRV_PCM_TRIGGER_STOP: |
505 | #ifdef CONFIG_PM | 505 | #ifdef CONFIG_PM |
506 | case SNDRV_PCM_TRIGGER_SUSPEND: | 506 | case SNDRV_PCM_TRIGGER_SUSPEND: |
507 | #endif | 507 | #endif |
508 | err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_PLAYBACK); | 508 | err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_PLAYBACK); |
509 | 509 | ||
510 | if (err < 0) | 510 | if (err < 0) |
511 | return err; | 511 | return err; |
512 | 512 | ||
513 | break; | 513 | break; |
514 | 514 | ||
515 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 515 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
516 | set_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags); | 516 | set_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags); |
517 | break; | 517 | break; |
518 | 518 | ||
519 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 519 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
520 | clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags); | 520 | clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags); |
521 | break; | 521 | break; |
522 | 522 | ||
523 | default: | 523 | default: |
524 | return -EINVAL; | 524 | return -EINVAL; |
525 | } | 525 | } |
526 | 526 | ||
527 | return 0; | 527 | return 0; |
528 | } | 528 | } |
529 | 529 | ||
530 | /* playback pointer callback */ | 530 | /* playback pointer callback */ |
531 | static snd_pcm_uframes_t | 531 | static snd_pcm_uframes_t |
532 | snd_line6_playback_pointer(struct snd_pcm_substream *substream) | 532 | snd_line6_playback_pointer(struct snd_pcm_substream *substream) |
533 | { | 533 | { |
534 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); | 534 | struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); |
535 | return line6pcm->pos_out_done; | 535 | return line6pcm->pos_out_done; |
536 | } | 536 | } |
537 | 537 | ||
538 | /* playback operators */ | 538 | /* playback operators */ |
539 | struct snd_pcm_ops snd_line6_playback_ops = { | 539 | struct snd_pcm_ops snd_line6_playback_ops = { |
540 | .open = snd_line6_playback_open, | 540 | .open = snd_line6_playback_open, |
541 | .close = snd_line6_playback_close, | 541 | .close = snd_line6_playback_close, |
542 | .ioctl = snd_pcm_lib_ioctl, | 542 | .ioctl = snd_pcm_lib_ioctl, |
543 | .hw_params = snd_line6_playback_hw_params, | 543 | .hw_params = snd_line6_playback_hw_params, |
544 | .hw_free = snd_line6_playback_hw_free, | 544 | .hw_free = snd_line6_playback_hw_free, |
545 | .prepare = snd_line6_prepare, | 545 | .prepare = snd_line6_prepare, |
546 | .trigger = snd_line6_trigger, | 546 | .trigger = snd_line6_trigger, |
547 | .pointer = snd_line6_playback_pointer, | 547 | .pointer = snd_line6_playback_pointer, |
548 | }; | 548 | }; |
549 | 549 | ||
550 | int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) | 550 | int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) |
551 | { | 551 | { |
552 | int i; | 552 | int i; |
553 | 553 | ||
554 | /* create audio URBs and fill in constant values: */ | 554 | /* create audio URBs and fill in constant values: */ |
555 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { | 555 | for (i = 0; i < LINE6_ISO_BUFFERS; ++i) { |
556 | struct urb *urb; | 556 | struct urb *urb; |
557 | 557 | ||
558 | /* URB for audio out: */ | 558 | /* URB for audio out: */ |
559 | urb = line6pcm->urb_audio_out[i] = | 559 | urb = line6pcm->urb_audio_out[i] = |
560 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); | 560 | usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); |
561 | 561 | ||
562 | if (urb == NULL) { | 562 | if (urb == NULL) { |
563 | dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); | 563 | dev_err(line6pcm->line6->ifcdev, "Out of memory\n"); |
564 | return -ENOMEM; | 564 | return -ENOMEM; |
565 | } | 565 | } |
566 | 566 | ||
567 | urb->dev = line6pcm->line6->usbdev; | 567 | urb->dev = line6pcm->line6->usbdev; |
568 | urb->pipe = | 568 | urb->pipe = |
569 | usb_sndisocpipe(line6pcm->line6->usbdev, | 569 | usb_sndisocpipe(line6pcm->line6->usbdev, |
570 | line6pcm->ep_audio_write & | 570 | line6pcm->ep_audio_write & |
571 | USB_ENDPOINT_NUMBER_MASK); | 571 | USB_ENDPOINT_NUMBER_MASK); |
572 | urb->transfer_flags = URB_ISO_ASAP; | 572 | urb->transfer_flags = URB_ISO_ASAP; |
573 | urb->start_frame = -1; | 573 | urb->start_frame = -1; |
574 | urb->number_of_packets = LINE6_ISO_PACKETS; | 574 | urb->number_of_packets = LINE6_ISO_PACKETS; |
575 | urb->interval = LINE6_ISO_INTERVAL; | 575 | urb->interval = LINE6_ISO_INTERVAL; |
576 | urb->error_count = 0; | 576 | urb->error_count = 0; |
577 | urb->complete = audio_out_callback; | 577 | urb->complete = audio_out_callback; |
578 | } | 578 | } |
579 | 579 | ||
580 | return 0; | 580 | return 0; |
581 | } | 581 | } |
582 | 582 |