diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-01-12 03:59:14 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-01-12 03:59:14 -0500 |
commit | 627b79628f56c3deeb17dec1edf6899b49552fa4 (patch) | |
tree | deac8b2cce5d70708fa944a270ee031f069226d8 /sound/core | |
parent | 29abceb67f8a230da806db4ed73899595bd2ae76 (diff) | |
parent | 8c3f5d8a9b7d0d8506bc2a0525e012eae02b1853 (diff) |
Merge branch 'topic/misc' into for-linus
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/Kconfig | 10 | ||||
-rw-r--r-- | sound/core/Makefile | 4 | ||||
-rw-r--r-- | sound/core/compress_offload.c | 765 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 2 | ||||
-rw-r--r-- | sound/core/seq/seq_dummy.c | 2 | ||||
-rw-r--r-- | sound/core/sound.c | 1 |
6 files changed, 782 insertions, 2 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 475455c76610..2dc7776e218c 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig | |||
@@ -155,6 +155,16 @@ config SND_DYNAMIC_MINORS | |||
155 | 155 | ||
156 | If you are unsure about this, say N here. | 156 | If you are unsure about this, say N here. |
157 | 157 | ||
158 | config SND_COMPRESS_OFFLOAD | ||
159 | tristate "ALSA Compressed audio offload support" | ||
160 | default n | ||
161 | help | ||
162 | If you want support for offloading compressed audio and have such | ||
163 | a hardware, then you should say Y here and also to the DSP driver | ||
164 | of your platform. | ||
165 | |||
166 | If you are unsure about this, say N here. | ||
167 | |||
158 | config SND_SUPPORT_OLD_API | 168 | config SND_SUPPORT_OLD_API |
159 | bool "Support old ALSA API" | 169 | bool "Support old ALSA API" |
160 | default y | 170 | default y |
diff --git a/sound/core/Makefile b/sound/core/Makefile index 350a08d277f4..67c8e9336611 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile | |||
@@ -21,6 +21,8 @@ snd-hrtimer-objs := hrtimer.o | |||
21 | snd-rtctimer-objs := rtctimer.o | 21 | snd-rtctimer-objs := rtctimer.o |
22 | snd-hwdep-objs := hwdep.o | 22 | snd-hwdep-objs := hwdep.o |
23 | 23 | ||
24 | snd-compress-objs := compress_offload.o | ||
25 | |||
24 | obj-$(CONFIG_SND) += snd.o | 26 | obj-$(CONFIG_SND) += snd.o |
25 | obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o | 27 | obj-$(CONFIG_SND_HWDEP) += snd-hwdep.o |
26 | obj-$(CONFIG_SND_TIMER) += snd-timer.o | 28 | obj-$(CONFIG_SND_TIMER) += snd-timer.o |
@@ -31,3 +33,5 @@ obj-$(CONFIG_SND_RAWMIDI) += snd-rawmidi.o | |||
31 | 33 | ||
32 | obj-$(CONFIG_SND_OSSEMUL) += oss/ | 34 | obj-$(CONFIG_SND_OSSEMUL) += oss/ |
33 | obj-$(CONFIG_SND_SEQUENCER) += seq/ | 35 | obj-$(CONFIG_SND_SEQUENCER) += seq/ |
36 | |||
37 | obj-$(CONFIG_SND_COMPRESS_OFFLOAD) += snd-compress.o | ||
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c new file mode 100644 index 000000000000..dac3633507c9 --- /dev/null +++ b/sound/core/compress_offload.c | |||
@@ -0,0 +1,765 @@ | |||
1 | /* | ||
2 | * compress_core.c - compress offload core | ||
3 | * | ||
4 | * Copyright (C) 2011 Intel Corporation | ||
5 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> | ||
6 | * Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | */ | ||
25 | #define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__ | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt) | ||
27 | |||
28 | #include <linux/file.h> | ||
29 | #include <linux/fs.h> | ||
30 | #include <linux/list.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/mutex.h> | ||
33 | #include <linux/poll.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/sched.h> | ||
36 | #include <linux/uio.h> | ||
37 | #include <linux/uaccess.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <sound/core.h> | ||
40 | #include <sound/initval.h> | ||
41 | #include <sound/compress_params.h> | ||
42 | #include <sound/compress_offload.h> | ||
43 | #include <sound/compress_driver.h> | ||
44 | |||
45 | /* TODO: | ||
46 | * - add substream support for multiple devices in case of | ||
47 | * SND_DYNAMIC_MINORS is not used | ||
48 | * - Multiple node representation | ||
49 | * driver should be able to register multiple nodes | ||
50 | */ | ||
51 | |||
52 | static DEFINE_MUTEX(device_mutex); | ||
53 | |||
54 | struct snd_compr_file { | ||
55 | unsigned long caps; | ||
56 | struct snd_compr_stream stream; | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * a note on stream states used: | ||
61 | * we use follwing states in the compressed core | ||
62 | * SNDRV_PCM_STATE_OPEN: When stream has been opened. | ||
63 | * SNDRV_PCM_STATE_SETUP: When stream has been initialized. This is done by | ||
64 | * calling SNDRV_COMPRESS_SET_PARAMS. running streams will come to this | ||
65 | * state at stop by calling SNDRV_COMPRESS_STOP, or at end of drain. | ||
66 | * SNDRV_PCM_STATE_RUNNING: When stream has been started and is | ||
67 | * decoding/encoding and rendering/capturing data. | ||
68 | * SNDRV_PCM_STATE_DRAINING: When stream is draining current data. This is done | ||
69 | * by calling SNDRV_COMPRESS_DRAIN. | ||
70 | * SNDRV_PCM_STATE_PAUSED: When stream is paused. This is done by calling | ||
71 | * SNDRV_COMPRESS_PAUSE. It can be stopped or resumed by calling | ||
72 | * SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively. | ||
73 | */ | ||
74 | static int snd_compr_open(struct inode *inode, struct file *f) | ||
75 | { | ||
76 | struct snd_compr *compr; | ||
77 | struct snd_compr_file *data; | ||
78 | struct snd_compr_runtime *runtime; | ||
79 | enum snd_compr_direction dirn; | ||
80 | int maj = imajor(inode); | ||
81 | int ret; | ||
82 | |||
83 | if (f->f_flags & O_WRONLY) | ||
84 | dirn = SND_COMPRESS_PLAYBACK; | ||
85 | else if (f->f_flags & O_RDONLY) | ||
86 | dirn = SND_COMPRESS_CAPTURE; | ||
87 | else { | ||
88 | pr_err("invalid direction\n"); | ||
89 | return -EINVAL; | ||
90 | } | ||
91 | |||
92 | if (maj == snd_major) | ||
93 | compr = snd_lookup_minor_data(iminor(inode), | ||
94 | SNDRV_DEVICE_TYPE_COMPRESS); | ||
95 | else | ||
96 | return -EBADFD; | ||
97 | |||
98 | if (compr == NULL) { | ||
99 | pr_err("no device data!!!\n"); | ||
100 | return -ENODEV; | ||
101 | } | ||
102 | |||
103 | if (dirn != compr->direction) { | ||
104 | pr_err("this device doesn't support this direction\n"); | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
108 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
109 | if (!data) | ||
110 | return -ENOMEM; | ||
111 | data->stream.ops = compr->ops; | ||
112 | data->stream.direction = dirn; | ||
113 | data->stream.private_data = compr->private_data; | ||
114 | data->stream.device = compr; | ||
115 | runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); | ||
116 | if (!runtime) { | ||
117 | kfree(data); | ||
118 | return -ENOMEM; | ||
119 | } | ||
120 | runtime->state = SNDRV_PCM_STATE_OPEN; | ||
121 | init_waitqueue_head(&runtime->sleep); | ||
122 | data->stream.runtime = runtime; | ||
123 | f->private_data = (void *)data; | ||
124 | mutex_lock(&compr->lock); | ||
125 | ret = compr->ops->open(&data->stream); | ||
126 | mutex_unlock(&compr->lock); | ||
127 | if (ret) { | ||
128 | kfree(runtime); | ||
129 | kfree(data); | ||
130 | } | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | static int snd_compr_free(struct inode *inode, struct file *f) | ||
135 | { | ||
136 | struct snd_compr_file *data = f->private_data; | ||
137 | data->stream.ops->free(&data->stream); | ||
138 | kfree(data->stream.runtime->buffer); | ||
139 | kfree(data->stream.runtime); | ||
140 | kfree(data); | ||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static void snd_compr_update_tstamp(struct snd_compr_stream *stream, | ||
145 | struct snd_compr_tstamp *tstamp) | ||
146 | { | ||
147 | if (!stream->ops->pointer) | ||
148 | return; | ||
149 | stream->ops->pointer(stream, tstamp); | ||
150 | pr_debug("dsp consumed till %d total %d bytes\n", | ||
151 | tstamp->byte_offset, tstamp->copied_total); | ||
152 | stream->runtime->hw_pointer = tstamp->byte_offset; | ||
153 | stream->runtime->total_bytes_transferred = tstamp->copied_total; | ||
154 | } | ||
155 | |||
156 | static size_t snd_compr_calc_avail(struct snd_compr_stream *stream, | ||
157 | struct snd_compr_avail *avail) | ||
158 | { | ||
159 | long avail_calc; /*this needs to be signed variable */ | ||
160 | |||
161 | snd_compr_update_tstamp(stream, &avail->tstamp); | ||
162 | |||
163 | /* FIXME: This needs to be different for capture stream, | ||
164 | available is # of compressed data, for playback it's | ||
165 | remainder of buffer */ | ||
166 | |||
167 | if (stream->runtime->total_bytes_available == 0 && | ||
168 | stream->runtime->state == SNDRV_PCM_STATE_SETUP) { | ||
169 | pr_debug("detected init and someone forgot to do a write\n"); | ||
170 | return stream->runtime->buffer_size; | ||
171 | } | ||
172 | pr_debug("app wrote %lld, DSP consumed %lld\n", | ||
173 | stream->runtime->total_bytes_available, | ||
174 | stream->runtime->total_bytes_transferred); | ||
175 | if (stream->runtime->total_bytes_available == | ||
176 | stream->runtime->total_bytes_transferred) { | ||
177 | pr_debug("both pointers are same, returning full avail\n"); | ||
178 | return stream->runtime->buffer_size; | ||
179 | } | ||
180 | |||
181 | /* FIXME: this routine isn't consistent, in one test we use | ||
182 | * cumulative values and in the other byte offsets. Do we | ||
183 | * really need the byte offsets if the cumulative values have | ||
184 | * been updated? In the PCM interface app_ptr and hw_ptr are | ||
185 | * already cumulative */ | ||
186 | |||
187 | avail_calc = stream->runtime->buffer_size - | ||
188 | (stream->runtime->app_pointer - stream->runtime->hw_pointer); | ||
189 | pr_debug("calc avail as %ld, app_ptr %lld, hw+ptr %lld\n", avail_calc, | ||
190 | stream->runtime->app_pointer, | ||
191 | stream->runtime->hw_pointer); | ||
192 | if (avail_calc >= stream->runtime->buffer_size) | ||
193 | avail_calc -= stream->runtime->buffer_size; | ||
194 | pr_debug("ret avail as %ld\n", avail_calc); | ||
195 | avail->avail = avail_calc; | ||
196 | return avail_calc; | ||
197 | } | ||
198 | |||
199 | static inline size_t snd_compr_get_avail(struct snd_compr_stream *stream) | ||
200 | { | ||
201 | struct snd_compr_avail avail; | ||
202 | |||
203 | return snd_compr_calc_avail(stream, &avail); | ||
204 | } | ||
205 | |||
206 | static int | ||
207 | snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) | ||
208 | { | ||
209 | struct snd_compr_avail ioctl_avail; | ||
210 | size_t avail; | ||
211 | |||
212 | avail = snd_compr_calc_avail(stream, &ioctl_avail); | ||
213 | ioctl_avail.avail = avail; | ||
214 | |||
215 | if (copy_to_user((__u64 __user *)arg, | ||
216 | &ioctl_avail, sizeof(ioctl_avail))) | ||
217 | return -EFAULT; | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int snd_compr_write_data(struct snd_compr_stream *stream, | ||
222 | const char __user *buf, size_t count) | ||
223 | { | ||
224 | void *dstn; | ||
225 | size_t copy; | ||
226 | struct snd_compr_runtime *runtime = stream->runtime; | ||
227 | |||
228 | dstn = runtime->buffer + runtime->app_pointer; | ||
229 | pr_debug("copying %ld at %lld\n", | ||
230 | (unsigned long)count, runtime->app_pointer); | ||
231 | if (count < runtime->buffer_size - runtime->app_pointer) { | ||
232 | if (copy_from_user(dstn, buf, count)) | ||
233 | return -EFAULT; | ||
234 | runtime->app_pointer += count; | ||
235 | } else { | ||
236 | copy = runtime->buffer_size - runtime->app_pointer; | ||
237 | if (copy_from_user(dstn, buf, copy)) | ||
238 | return -EFAULT; | ||
239 | if (copy_from_user(runtime->buffer, buf + copy, count - copy)) | ||
240 | return -EFAULT; | ||
241 | runtime->app_pointer = count - copy; | ||
242 | } | ||
243 | /* if DSP cares, let it know data has been written */ | ||
244 | if (stream->ops->ack) | ||
245 | stream->ops->ack(stream, count); | ||
246 | return count; | ||
247 | } | ||
248 | |||
249 | static ssize_t snd_compr_write(struct file *f, const char __user *buf, | ||
250 | size_t count, loff_t *offset) | ||
251 | { | ||
252 | struct snd_compr_file *data = f->private_data; | ||
253 | struct snd_compr_stream *stream; | ||
254 | size_t avail; | ||
255 | int retval; | ||
256 | |||
257 | if (snd_BUG_ON(!data)) | ||
258 | return -EFAULT; | ||
259 | |||
260 | stream = &data->stream; | ||
261 | mutex_lock(&stream->device->lock); | ||
262 | /* write is allowed when stream is running or has been steup */ | ||
263 | if (stream->runtime->state != SNDRV_PCM_STATE_SETUP && | ||
264 | stream->runtime->state != SNDRV_PCM_STATE_RUNNING) { | ||
265 | mutex_unlock(&stream->device->lock); | ||
266 | return -EBADFD; | ||
267 | } | ||
268 | |||
269 | avail = snd_compr_get_avail(stream); | ||
270 | pr_debug("avail returned %ld\n", (unsigned long)avail); | ||
271 | /* calculate how much we can write to buffer */ | ||
272 | if (avail > count) | ||
273 | avail = count; | ||
274 | |||
275 | if (stream->ops->copy) | ||
276 | retval = stream->ops->copy(stream, buf, avail); | ||
277 | else | ||
278 | retval = snd_compr_write_data(stream, buf, avail); | ||
279 | if (retval > 0) | ||
280 | stream->runtime->total_bytes_available += retval; | ||
281 | |||
282 | /* while initiating the stream, write should be called before START | ||
283 | * call, so in setup move state */ | ||
284 | if (stream->runtime->state == SNDRV_PCM_STATE_SETUP) { | ||
285 | stream->runtime->state = SNDRV_PCM_STATE_PREPARED; | ||
286 | pr_debug("stream prepared, Houston we are good to go\n"); | ||
287 | } | ||
288 | |||
289 | mutex_unlock(&stream->device->lock); | ||
290 | return retval; | ||
291 | } | ||
292 | |||
293 | |||
294 | static ssize_t snd_compr_read(struct file *f, char __user *buf, | ||
295 | size_t count, loff_t *offset) | ||
296 | { | ||
297 | return -ENXIO; | ||
298 | } | ||
299 | |||
300 | static int snd_compr_mmap(struct file *f, struct vm_area_struct *vma) | ||
301 | { | ||
302 | return -ENXIO; | ||
303 | } | ||
304 | |||
305 | static inline int snd_compr_get_poll(struct snd_compr_stream *stream) | ||
306 | { | ||
307 | if (stream->direction == SND_COMPRESS_PLAYBACK) | ||
308 | return POLLOUT | POLLWRNORM; | ||
309 | else | ||
310 | return POLLIN | POLLRDNORM; | ||
311 | } | ||
312 | |||
313 | static unsigned int snd_compr_poll(struct file *f, poll_table *wait) | ||
314 | { | ||
315 | struct snd_compr_file *data = f->private_data; | ||
316 | struct snd_compr_stream *stream; | ||
317 | size_t avail; | ||
318 | int retval = 0; | ||
319 | |||
320 | if (snd_BUG_ON(!data)) | ||
321 | return -EFAULT; | ||
322 | stream = &data->stream; | ||
323 | if (snd_BUG_ON(!stream)) | ||
324 | return -EFAULT; | ||
325 | |||
326 | mutex_lock(&stream->device->lock); | ||
327 | if (stream->runtime->state == SNDRV_PCM_STATE_PAUSED || | ||
328 | stream->runtime->state == SNDRV_PCM_STATE_OPEN) { | ||
329 | retval = -EBADFD; | ||
330 | goto out; | ||
331 | } | ||
332 | poll_wait(f, &stream->runtime->sleep, wait); | ||
333 | |||
334 | avail = snd_compr_get_avail(stream); | ||
335 | pr_debug("avail is %ld\n", (unsigned long)avail); | ||
336 | /* check if we have at least one fragment to fill */ | ||
337 | switch (stream->runtime->state) { | ||
338 | case SNDRV_PCM_STATE_DRAINING: | ||
339 | /* stream has been woken up after drain is complete | ||
340 | * draining done so set stream state to stopped | ||
341 | */ | ||
342 | retval = snd_compr_get_poll(stream); | ||
343 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; | ||
344 | break; | ||
345 | case SNDRV_PCM_STATE_RUNNING: | ||
346 | case SNDRV_PCM_STATE_PREPARED: | ||
347 | case SNDRV_PCM_STATE_PAUSED: | ||
348 | if (avail >= stream->runtime->fragment_size) | ||
349 | retval = snd_compr_get_poll(stream); | ||
350 | break; | ||
351 | default: | ||
352 | if (stream->direction == SND_COMPRESS_PLAYBACK) | ||
353 | retval = POLLOUT | POLLWRNORM | POLLERR; | ||
354 | else | ||
355 | retval = POLLIN | POLLRDNORM | POLLERR; | ||
356 | break; | ||
357 | } | ||
358 | out: | ||
359 | mutex_unlock(&stream->device->lock); | ||
360 | return retval; | ||
361 | } | ||
362 | |||
363 | static int | ||
364 | snd_compr_get_caps(struct snd_compr_stream *stream, unsigned long arg) | ||
365 | { | ||
366 | int retval; | ||
367 | struct snd_compr_caps caps; | ||
368 | |||
369 | if (!stream->ops->get_caps) | ||
370 | return -ENXIO; | ||
371 | |||
372 | retval = stream->ops->get_caps(stream, &caps); | ||
373 | if (retval) | ||
374 | goto out; | ||
375 | if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) | ||
376 | retval = -EFAULT; | ||
377 | out: | ||
378 | return retval; | ||
379 | } | ||
380 | |||
381 | static int | ||
382 | snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg) | ||
383 | { | ||
384 | int retval; | ||
385 | struct snd_compr_codec_caps *caps; | ||
386 | |||
387 | if (!stream->ops->get_codec_caps) | ||
388 | return -ENXIO; | ||
389 | |||
390 | caps = kmalloc(sizeof(*caps), GFP_KERNEL); | ||
391 | if (!caps) | ||
392 | return -ENOMEM; | ||
393 | |||
394 | retval = stream->ops->get_codec_caps(stream, caps); | ||
395 | if (retval) | ||
396 | goto out; | ||
397 | if (copy_to_user((void __user *)arg, caps, sizeof(*caps))) | ||
398 | retval = -EFAULT; | ||
399 | |||
400 | out: | ||
401 | kfree(caps); | ||
402 | return retval; | ||
403 | } | ||
404 | |||
405 | /* revisit this with snd_pcm_preallocate_xxx */ | ||
406 | static int snd_compr_allocate_buffer(struct snd_compr_stream *stream, | ||
407 | struct snd_compr_params *params) | ||
408 | { | ||
409 | unsigned int buffer_size; | ||
410 | void *buffer; | ||
411 | |||
412 | buffer_size = params->buffer.fragment_size * params->buffer.fragments; | ||
413 | if (stream->ops->copy) { | ||
414 | buffer = NULL; | ||
415 | /* if copy is defined the driver will be required to copy | ||
416 | * the data from core | ||
417 | */ | ||
418 | } else { | ||
419 | buffer = kmalloc(buffer_size, GFP_KERNEL); | ||
420 | if (!buffer) | ||
421 | return -ENOMEM; | ||
422 | } | ||
423 | stream->runtime->fragment_size = params->buffer.fragment_size; | ||
424 | stream->runtime->fragments = params->buffer.fragments; | ||
425 | stream->runtime->buffer = buffer; | ||
426 | stream->runtime->buffer_size = buffer_size; | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int | ||
431 | snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg) | ||
432 | { | ||
433 | struct snd_compr_params *params; | ||
434 | int retval; | ||
435 | |||
436 | if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) { | ||
437 | /* | ||
438 | * we should allow parameter change only when stream has been | ||
439 | * opened not in other cases | ||
440 | */ | ||
441 | params = kmalloc(sizeof(*params), GFP_KERNEL); | ||
442 | if (!params) | ||
443 | return -ENOMEM; | ||
444 | if (copy_from_user(params, (void __user *)arg, sizeof(*params))) | ||
445 | return -EFAULT; | ||
446 | retval = snd_compr_allocate_buffer(stream, params); | ||
447 | if (retval) { | ||
448 | kfree(params); | ||
449 | return -ENOMEM; | ||
450 | } | ||
451 | retval = stream->ops->set_params(stream, params); | ||
452 | if (retval) | ||
453 | goto out; | ||
454 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; | ||
455 | } else | ||
456 | return -EPERM; | ||
457 | out: | ||
458 | kfree(params); | ||
459 | return retval; | ||
460 | } | ||
461 | |||
462 | static int | ||
463 | snd_compr_get_params(struct snd_compr_stream *stream, unsigned long arg) | ||
464 | { | ||
465 | struct snd_codec *params; | ||
466 | int retval; | ||
467 | |||
468 | if (!stream->ops->get_params) | ||
469 | return -EBADFD; | ||
470 | |||
471 | params = kmalloc(sizeof(*params), GFP_KERNEL); | ||
472 | if (!params) | ||
473 | return -ENOMEM; | ||
474 | retval = stream->ops->get_params(stream, params); | ||
475 | if (retval) | ||
476 | goto out; | ||
477 | if (copy_to_user((char __user *)arg, params, sizeof(*params))) | ||
478 | retval = -EFAULT; | ||
479 | |||
480 | out: | ||
481 | kfree(params); | ||
482 | return retval; | ||
483 | } | ||
484 | |||
485 | static inline int | ||
486 | snd_compr_tstamp(struct snd_compr_stream *stream, unsigned long arg) | ||
487 | { | ||
488 | struct snd_compr_tstamp tstamp; | ||
489 | |||
490 | snd_compr_update_tstamp(stream, &tstamp); | ||
491 | return copy_to_user((struct snd_compr_tstamp __user *)arg, | ||
492 | &tstamp, sizeof(tstamp)) ? -EFAULT : 0; | ||
493 | } | ||
494 | |||
495 | static int snd_compr_pause(struct snd_compr_stream *stream) | ||
496 | { | ||
497 | int retval; | ||
498 | |||
499 | if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) | ||
500 | return -EPERM; | ||
501 | retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); | ||
502 | if (!retval) { | ||
503 | stream->runtime->state = SNDRV_PCM_STATE_PAUSED; | ||
504 | wake_up(&stream->runtime->sleep); | ||
505 | } | ||
506 | return retval; | ||
507 | } | ||
508 | |||
509 | static int snd_compr_resume(struct snd_compr_stream *stream) | ||
510 | { | ||
511 | int retval; | ||
512 | |||
513 | if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED) | ||
514 | return -EPERM; | ||
515 | retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); | ||
516 | if (!retval) | ||
517 | stream->runtime->state = SNDRV_PCM_STATE_RUNNING; | ||
518 | return retval; | ||
519 | } | ||
520 | |||
521 | static int snd_compr_start(struct snd_compr_stream *stream) | ||
522 | { | ||
523 | int retval; | ||
524 | |||
525 | if (stream->runtime->state != SNDRV_PCM_STATE_PREPARED) | ||
526 | return -EPERM; | ||
527 | retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_START); | ||
528 | if (!retval) | ||
529 | stream->runtime->state = SNDRV_PCM_STATE_RUNNING; | ||
530 | return retval; | ||
531 | } | ||
532 | |||
533 | static int snd_compr_stop(struct snd_compr_stream *stream) | ||
534 | { | ||
535 | int retval; | ||
536 | |||
537 | if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || | ||
538 | stream->runtime->state == SNDRV_PCM_STATE_SETUP) | ||
539 | return -EPERM; | ||
540 | retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); | ||
541 | if (!retval) { | ||
542 | stream->runtime->state = SNDRV_PCM_STATE_SETUP; | ||
543 | wake_up(&stream->runtime->sleep); | ||
544 | } | ||
545 | return retval; | ||
546 | } | ||
547 | |||
548 | static int snd_compr_drain(struct snd_compr_stream *stream) | ||
549 | { | ||
550 | int retval; | ||
551 | |||
552 | if (stream->runtime->state == SNDRV_PCM_STATE_PREPARED || | ||
553 | stream->runtime->state == SNDRV_PCM_STATE_SETUP) | ||
554 | return -EPERM; | ||
555 | retval = stream->ops->trigger(stream, SND_COMPR_TRIGGER_DRAIN); | ||
556 | if (!retval) { | ||
557 | stream->runtime->state = SNDRV_PCM_STATE_DRAINING; | ||
558 | wake_up(&stream->runtime->sleep); | ||
559 | } | ||
560 | return retval; | ||
561 | } | ||
562 | |||
563 | static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
564 | { | ||
565 | struct snd_compr_file *data = f->private_data; | ||
566 | struct snd_compr_stream *stream; | ||
567 | int retval = -ENOTTY; | ||
568 | |||
569 | if (snd_BUG_ON(!data)) | ||
570 | return -EFAULT; | ||
571 | stream = &data->stream; | ||
572 | if (snd_BUG_ON(!stream)) | ||
573 | return -EFAULT; | ||
574 | mutex_lock(&stream->device->lock); | ||
575 | switch (_IOC_NR(cmd)) { | ||
576 | case _IOC_NR(SNDRV_COMPRESS_IOCTL_VERSION): | ||
577 | put_user(SNDRV_COMPRESS_VERSION, | ||
578 | (int __user *)arg) ? -EFAULT : 0; | ||
579 | break; | ||
580 | case _IOC_NR(SNDRV_COMPRESS_GET_CAPS): | ||
581 | retval = snd_compr_get_caps(stream, arg); | ||
582 | break; | ||
583 | case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS): | ||
584 | retval = snd_compr_get_codec_caps(stream, arg); | ||
585 | break; | ||
586 | case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS): | ||
587 | retval = snd_compr_set_params(stream, arg); | ||
588 | break; | ||
589 | case _IOC_NR(SNDRV_COMPRESS_GET_PARAMS): | ||
590 | retval = snd_compr_get_params(stream, arg); | ||
591 | break; | ||
592 | case _IOC_NR(SNDRV_COMPRESS_TSTAMP): | ||
593 | retval = snd_compr_tstamp(stream, arg); | ||
594 | break; | ||
595 | case _IOC_NR(SNDRV_COMPRESS_AVAIL): | ||
596 | retval = snd_compr_ioctl_avail(stream, arg); | ||
597 | break; | ||
598 | case _IOC_NR(SNDRV_COMPRESS_PAUSE): | ||
599 | retval = snd_compr_pause(stream); | ||
600 | break; | ||
601 | case _IOC_NR(SNDRV_COMPRESS_RESUME): | ||
602 | retval = snd_compr_resume(stream); | ||
603 | break; | ||
604 | case _IOC_NR(SNDRV_COMPRESS_START): | ||
605 | retval = snd_compr_start(stream); | ||
606 | break; | ||
607 | case _IOC_NR(SNDRV_COMPRESS_STOP): | ||
608 | retval = snd_compr_stop(stream); | ||
609 | break; | ||
610 | case _IOC_NR(SNDRV_COMPRESS_DRAIN): | ||
611 | retval = snd_compr_drain(stream); | ||
612 | break; | ||
613 | } | ||
614 | mutex_unlock(&stream->device->lock); | ||
615 | return retval; | ||
616 | } | ||
617 | |||
618 | static const struct file_operations snd_compr_file_ops = { | ||
619 | .owner = THIS_MODULE, | ||
620 | .open = snd_compr_open, | ||
621 | .release = snd_compr_free, | ||
622 | .write = snd_compr_write, | ||
623 | .read = snd_compr_read, | ||
624 | .unlocked_ioctl = snd_compr_ioctl, | ||
625 | .mmap = snd_compr_mmap, | ||
626 | .poll = snd_compr_poll, | ||
627 | }; | ||
628 | |||
629 | static int snd_compress_dev_register(struct snd_device *device) | ||
630 | { | ||
631 | int ret = -EINVAL; | ||
632 | char str[16]; | ||
633 | struct snd_compr *compr; | ||
634 | |||
635 | if (snd_BUG_ON(!device || !device->device_data)) | ||
636 | return -EBADFD; | ||
637 | compr = device->device_data; | ||
638 | |||
639 | sprintf(str, "comprC%iD%i", compr->card->number, compr->device); | ||
640 | pr_debug("reg %s for device %s, direction %d\n", str, compr->name, | ||
641 | compr->direction); | ||
642 | /* register compressed device */ | ||
643 | ret = snd_register_device(SNDRV_DEVICE_TYPE_COMPRESS, compr->card, | ||
644 | compr->device, &snd_compr_file_ops, compr, str); | ||
645 | if (ret < 0) { | ||
646 | pr_err("snd_register_device failed\n %d", ret); | ||
647 | return ret; | ||
648 | } | ||
649 | return ret; | ||
650 | |||
651 | } | ||
652 | |||
653 | static int snd_compress_dev_disconnect(struct snd_device *device) | ||
654 | { | ||
655 | struct snd_compr *compr; | ||
656 | |||
657 | compr = device->device_data; | ||
658 | snd_unregister_device(compr->direction, compr->card, compr->device); | ||
659 | return 0; | ||
660 | } | ||
661 | |||
662 | /* | ||
663 | * snd_compress_new: create new compress device | ||
664 | * @card: sound card pointer | ||
665 | * @device: device number | ||
666 | * @dirn: device direction, should be of type enum snd_compr_direction | ||
667 | * @compr: compress device pointer | ||
668 | */ | ||
669 | int snd_compress_new(struct snd_card *card, int device, | ||
670 | int dirn, struct snd_compr *compr) | ||
671 | { | ||
672 | static struct snd_device_ops ops = { | ||
673 | .dev_free = NULL, | ||
674 | .dev_register = snd_compress_dev_register, | ||
675 | .dev_disconnect = snd_compress_dev_disconnect, | ||
676 | }; | ||
677 | |||
678 | compr->card = card; | ||
679 | compr->device = device; | ||
680 | compr->direction = dirn; | ||
681 | return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); | ||
682 | } | ||
683 | EXPORT_SYMBOL_GPL(snd_compress_new); | ||
684 | |||
685 | static int snd_compress_add_device(struct snd_compr *device) | ||
686 | { | ||
687 | int ret; | ||
688 | |||
689 | if (!device->card) | ||
690 | return -EINVAL; | ||
691 | |||
692 | /* register the card */ | ||
693 | ret = snd_card_register(device->card); | ||
694 | if (ret) | ||
695 | goto out; | ||
696 | return 0; | ||
697 | |||
698 | out: | ||
699 | pr_err("failed with %d\n", ret); | ||
700 | return ret; | ||
701 | |||
702 | } | ||
703 | |||
704 | static int snd_compress_remove_device(struct snd_compr *device) | ||
705 | { | ||
706 | return snd_card_free(device->card); | ||
707 | } | ||
708 | |||
709 | /** | ||
710 | * snd_compress_register - register compressed device | ||
711 | * | ||
712 | * @device: compressed device to register | ||
713 | */ | ||
714 | int snd_compress_register(struct snd_compr *device) | ||
715 | { | ||
716 | int retval; | ||
717 | |||
718 | if (device->name == NULL || device->dev == NULL || device->ops == NULL) | ||
719 | return -EINVAL; | ||
720 | |||
721 | pr_debug("Registering compressed device %s\n", device->name); | ||
722 | if (snd_BUG_ON(!device->ops->open)) | ||
723 | return -EINVAL; | ||
724 | if (snd_BUG_ON(!device->ops->free)) | ||
725 | return -EINVAL; | ||
726 | if (snd_BUG_ON(!device->ops->set_params)) | ||
727 | return -EINVAL; | ||
728 | if (snd_BUG_ON(!device->ops->trigger)) | ||
729 | return -EINVAL; | ||
730 | |||
731 | mutex_init(&device->lock); | ||
732 | |||
733 | /* register a compressed card */ | ||
734 | mutex_lock(&device_mutex); | ||
735 | retval = snd_compress_add_device(device); | ||
736 | mutex_unlock(&device_mutex); | ||
737 | return retval; | ||
738 | } | ||
739 | EXPORT_SYMBOL_GPL(snd_compress_register); | ||
740 | |||
741 | int snd_compress_deregister(struct snd_compr *device) | ||
742 | { | ||
743 | pr_debug("Removing compressed device %s\n", device->name); | ||
744 | mutex_lock(&device_mutex); | ||
745 | snd_compress_remove_device(device); | ||
746 | mutex_unlock(&device_mutex); | ||
747 | return 0; | ||
748 | } | ||
749 | EXPORT_SYMBOL_GPL(snd_compress_deregister); | ||
750 | |||
751 | static int __init snd_compress_init(void) | ||
752 | { | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static void __exit snd_compress_exit(void) | ||
757 | { | ||
758 | } | ||
759 | |||
760 | module_init(snd_compress_init); | ||
761 | module_exit(snd_compress_exit); | ||
762 | |||
763 | MODULE_DESCRIPTION("ALSA Compressed offload framework"); | ||
764 | MODULE_AUTHOR("Vinod Koul <vinod.koul@linux.intel.com>"); | ||
765 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 3cc4b86dfb7e..08fde0060fd9 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -47,7 +47,7 @@ | |||
47 | 47 | ||
48 | static int dsp_map[SNDRV_CARDS]; | 48 | static int dsp_map[SNDRV_CARDS]; |
49 | static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; | 49 | static int adsp_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1}; |
50 | static int nonblock_open = 1; | 50 | static bool nonblock_open = 1; |
51 | 51 | ||
52 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); | 52 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>"); |
53 | MODULE_DESCRIPTION("PCM OSS emulation for ALSA."); | 53 | MODULE_DESCRIPTION("PCM OSS emulation for ALSA."); |
diff --git a/sound/core/seq/seq_dummy.c b/sound/core/seq/seq_dummy.c index b9b2235d9ab1..bbe32d2177d9 100644 --- a/sound/core/seq/seq_dummy.c +++ b/sound/core/seq/seq_dummy.c | |||
@@ -65,7 +65,7 @@ MODULE_LICENSE("GPL"); | |||
65 | MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY)); | 65 | MODULE_ALIAS("snd-seq-client-" __stringify(SNDRV_SEQ_CLIENT_DUMMY)); |
66 | 66 | ||
67 | static int ports = 1; | 67 | static int ports = 1; |
68 | static int duplex; | 68 | static bool duplex; |
69 | 69 | ||
70 | module_param(ports, int, 0444); | 70 | module_param(ports, int, 0444); |
71 | MODULE_PARM_DESC(ports, "number of ports to be created"); | 71 | MODULE_PARM_DESC(ports, "number of ports to be created"); |
diff --git a/sound/core/sound.c b/sound/core/sound.c index 828af353ea9f..28f35593a750 100644 --- a/sound/core/sound.c +++ b/sound/core/sound.c | |||
@@ -229,6 +229,7 @@ static int snd_kernel_minor(int type, struct snd_card *card, int dev) | |||
229 | case SNDRV_DEVICE_TYPE_RAWMIDI: | 229 | case SNDRV_DEVICE_TYPE_RAWMIDI: |
230 | case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: | 230 | case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: |
231 | case SNDRV_DEVICE_TYPE_PCM_CAPTURE: | 231 | case SNDRV_DEVICE_TYPE_PCM_CAPTURE: |
232 | case SNDRV_DEVICE_TYPE_COMPRESS: | ||
232 | if (snd_BUG_ON(!card)) | 233 | if (snd_BUG_ON(!card)) |
233 | return -EINVAL; | 234 | return -EINVAL; |
234 | minor = SNDRV_MINOR(card->number, type + dev); | 235 | minor = SNDRV_MINOR(card->number, type + dev); |