diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/oss/audio.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/oss/audio.c')
-rw-r--r-- | sound/oss/audio.c | 983 |
1 files changed, 983 insertions, 0 deletions
diff --git a/sound/oss/audio.c b/sound/oss/audio.c new file mode 100644 index 000000000000..22dd63c36816 --- /dev/null +++ b/sound/oss/audio.c | |||
@@ -0,0 +1,983 @@ | |||
1 | /* | ||
2 | * sound/audio.c | ||
3 | * | ||
4 | * Device file manager for /dev/audio | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) by Hannu Savolainen 1993-1997 | ||
9 | * | ||
10 | * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) | ||
11 | * Version 2 (June 1991). See the "COPYING" file distributed with this software | ||
12 | * for more info. | ||
13 | */ | ||
14 | /* | ||
15 | * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) | ||
16 | * Thomas Sailer : moved several static variables into struct audio_operations | ||
17 | * (which is grossly misnamed btw.) because they have the same | ||
18 | * lifetime as the rest in there and dynamic allocation saves | ||
19 | * 12k or so | ||
20 | * Thomas Sailer : use more logical O_NONBLOCK semantics | ||
21 | * Daniel Rodriksson: reworked the use of the device specific copy_user | ||
22 | * still generic | ||
23 | * Horst von Brand: Add missing #include <linux/string.h> | ||
24 | * Chris Rankin : Update the module-usage counter for the coprocessor, | ||
25 | * and decrement the counters again if we cannot open | ||
26 | * the audio device. | ||
27 | */ | ||
28 | |||
29 | #include <linux/stddef.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/kmod.h> | ||
32 | |||
33 | #include "sound_config.h" | ||
34 | #include "ulaw.h" | ||
35 | #include "coproc.h" | ||
36 | |||
37 | #define NEUTRAL8 0x80 | ||
38 | #define NEUTRAL16 0x00 | ||
39 | |||
40 | |||
41 | static int dma_ioctl(int dev, unsigned int cmd, void __user *arg); | ||
42 | |||
43 | static int set_format(int dev, int fmt) | ||
44 | { | ||
45 | if (fmt != AFMT_QUERY) | ||
46 | { | ||
47 | audio_devs[dev]->local_conversion = 0; | ||
48 | |||
49 | if (!(audio_devs[dev]->format_mask & fmt)) /* Not supported */ | ||
50 | { | ||
51 | if (fmt == AFMT_MU_LAW) | ||
52 | { | ||
53 | fmt = AFMT_U8; | ||
54 | audio_devs[dev]->local_conversion = CNV_MU_LAW; | ||
55 | } | ||
56 | else | ||
57 | fmt = AFMT_U8; /* This is always supported */ | ||
58 | } | ||
59 | audio_devs[dev]->audio_format = audio_devs[dev]->d->set_bits(dev, fmt); | ||
60 | audio_devs[dev]->local_format = fmt; | ||
61 | } | ||
62 | else | ||
63 | return audio_devs[dev]->local_format; | ||
64 | |||
65 | if (audio_devs[dev]->local_conversion) | ||
66 | return audio_devs[dev]->local_conversion; | ||
67 | else | ||
68 | return audio_devs[dev]->local_format; | ||
69 | } | ||
70 | |||
71 | int audio_open(int dev, struct file *file) | ||
72 | { | ||
73 | int ret; | ||
74 | int bits; | ||
75 | int dev_type = dev & 0x0f; | ||
76 | int mode = translate_mode(file); | ||
77 | const struct audio_driver *driver; | ||
78 | const struct coproc_operations *coprocessor; | ||
79 | |||
80 | dev = dev >> 4; | ||
81 | |||
82 | if (dev_type == SND_DEV_DSP16) | ||
83 | bits = 16; | ||
84 | else | ||
85 | bits = 8; | ||
86 | |||
87 | if (dev < 0 || dev >= num_audiodevs) | ||
88 | return -ENXIO; | ||
89 | |||
90 | driver = audio_devs[dev]->d; | ||
91 | |||
92 | if (!try_module_get(driver->owner)) | ||
93 | return -ENODEV; | ||
94 | |||
95 | if ((ret = DMAbuf_open(dev, mode)) < 0) | ||
96 | goto error_1; | ||
97 | |||
98 | if ( (coprocessor = audio_devs[dev]->coproc) != NULL ) { | ||
99 | if (!try_module_get(coprocessor->owner)) | ||
100 | goto error_2; | ||
101 | |||
102 | if ((ret = coprocessor->open(coprocessor->devc, COPR_PCM)) < 0) { | ||
103 | printk(KERN_WARNING "Sound: Can't access coprocessor device\n"); | ||
104 | goto error_3; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | audio_devs[dev]->local_conversion = 0; | ||
109 | |||
110 | if (dev_type == SND_DEV_AUDIO) | ||
111 | set_format(dev, AFMT_MU_LAW); | ||
112 | else | ||
113 | set_format(dev, bits); | ||
114 | |||
115 | audio_devs[dev]->audio_mode = AM_NONE; | ||
116 | |||
117 | return 0; | ||
118 | |||
119 | /* | ||
120 | * Clean-up stack: this is what needs (un)doing if | ||
121 | * we can't open the audio device ... | ||
122 | */ | ||
123 | error_3: | ||
124 | module_put(coprocessor->owner); | ||
125 | |||
126 | error_2: | ||
127 | DMAbuf_release(dev, mode); | ||
128 | |||
129 | error_1: | ||
130 | module_put(driver->owner); | ||
131 | |||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | static void sync_output(int dev) | ||
136 | { | ||
137 | int p, i; | ||
138 | int l; | ||
139 | struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; | ||
140 | |||
141 | if (dmap->fragment_size <= 0) | ||
142 | return; | ||
143 | dmap->flags |= DMA_POST; | ||
144 | |||
145 | /* Align the write pointer with fragment boundaries */ | ||
146 | |||
147 | if ((l = dmap->user_counter % dmap->fragment_size) > 0) | ||
148 | { | ||
149 | int len; | ||
150 | unsigned long offs = dmap->user_counter % dmap->bytes_in_use; | ||
151 | |||
152 | len = dmap->fragment_size - l; | ||
153 | memset(dmap->raw_buf + offs, dmap->neutral_byte, len); | ||
154 | DMAbuf_move_wrpointer(dev, len); | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Clean all unused buffer fragments. | ||
159 | */ | ||
160 | |||
161 | p = dmap->qtail; | ||
162 | dmap->flags |= DMA_POST; | ||
163 | |||
164 | for (i = dmap->qlen + 1; i < dmap->nbufs; i++) | ||
165 | { | ||
166 | p = (p + 1) % dmap->nbufs; | ||
167 | if (((dmap->raw_buf + p * dmap->fragment_size) + dmap->fragment_size) > | ||
168 | (dmap->raw_buf + dmap->buffsize)) | ||
169 | printk(KERN_ERR "audio: Buffer error 2\n"); | ||
170 | |||
171 | memset(dmap->raw_buf + p * dmap->fragment_size, | ||
172 | dmap->neutral_byte, | ||
173 | dmap->fragment_size); | ||
174 | } | ||
175 | |||
176 | dmap->flags |= DMA_DIRTY; | ||
177 | } | ||
178 | |||
179 | void audio_release(int dev, struct file *file) | ||
180 | { | ||
181 | const struct coproc_operations *coprocessor; | ||
182 | int mode = translate_mode(file); | ||
183 | |||
184 | dev = dev >> 4; | ||
185 | |||
186 | /* | ||
187 | * We do this in DMAbuf_release(). Why are we doing it | ||
188 | * here? Why don't we test the file mode before setting | ||
189 | * both flags? DMAbuf_release() does. | ||
190 | * ...pester...pester...pester... | ||
191 | */ | ||
192 | audio_devs[dev]->dmap_out->closing = 1; | ||
193 | audio_devs[dev]->dmap_in->closing = 1; | ||
194 | |||
195 | /* | ||
196 | * We need to make sure we allocated the dmap_out buffer | ||
197 | * before we go mucking around with it in sync_output(). | ||
198 | */ | ||
199 | if (mode & OPEN_WRITE) | ||
200 | sync_output(dev); | ||
201 | |||
202 | if ( (coprocessor = audio_devs[dev]->coproc) != NULL ) { | ||
203 | coprocessor->close(coprocessor->devc, COPR_PCM); | ||
204 | module_put(coprocessor->owner); | ||
205 | } | ||
206 | DMAbuf_release(dev, mode); | ||
207 | |||
208 | module_put(audio_devs[dev]->d->owner); | ||
209 | } | ||
210 | |||
211 | static void translate_bytes(const unsigned char *table, unsigned char *buff, int n) | ||
212 | { | ||
213 | unsigned long i; | ||
214 | |||
215 | if (n <= 0) | ||
216 | return; | ||
217 | |||
218 | for (i = 0; i < n; ++i) | ||
219 | buff[i] = table[buff[i]]; | ||
220 | } | ||
221 | |||
222 | int audio_write(int dev, struct file *file, const char __user *buf, int count) | ||
223 | { | ||
224 | int c, p, l, buf_size, used, returned; | ||
225 | int err; | ||
226 | char *dma_buf; | ||
227 | |||
228 | dev = dev >> 4; | ||
229 | |||
230 | p = 0; | ||
231 | c = count; | ||
232 | |||
233 | if(count < 0) | ||
234 | return -EINVAL; | ||
235 | |||
236 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
237 | return -EPERM; | ||
238 | |||
239 | if (audio_devs[dev]->flags & DMA_DUPLEX) | ||
240 | audio_devs[dev]->audio_mode |= AM_WRITE; | ||
241 | else | ||
242 | audio_devs[dev]->audio_mode = AM_WRITE; | ||
243 | |||
244 | if (!count) /* Flush output */ | ||
245 | { | ||
246 | sync_output(dev); | ||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | while (c) | ||
251 | { | ||
252 | if ((err = DMAbuf_getwrbuffer(dev, &dma_buf, &buf_size, !!(file->f_flags & O_NONBLOCK))) < 0) | ||
253 | { | ||
254 | /* Handle nonblocking mode */ | ||
255 | if ((file->f_flags & O_NONBLOCK) && err == -EAGAIN) | ||
256 | return p? p : -EAGAIN; /* No more space. Return # of accepted bytes */ | ||
257 | return err; | ||
258 | } | ||
259 | l = c; | ||
260 | |||
261 | if (l > buf_size) | ||
262 | l = buf_size; | ||
263 | |||
264 | returned = l; | ||
265 | used = l; | ||
266 | if (!audio_devs[dev]->d->copy_user) | ||
267 | { | ||
268 | if ((dma_buf + l) > | ||
269 | (audio_devs[dev]->dmap_out->raw_buf + audio_devs[dev]->dmap_out->buffsize)) | ||
270 | { | ||
271 | printk(KERN_ERR "audio: Buffer error 3 (%lx,%d), (%lx, %d)\n", (long) dma_buf, l, (long) audio_devs[dev]->dmap_out->raw_buf, (int) audio_devs[dev]->dmap_out->buffsize); | ||
272 | return -EDOM; | ||
273 | } | ||
274 | if (dma_buf < audio_devs[dev]->dmap_out->raw_buf) | ||
275 | { | ||
276 | printk(KERN_ERR "audio: Buffer error 13 (%lx<%lx)\n", (long) dma_buf, (long) audio_devs[dev]->dmap_out->raw_buf); | ||
277 | return -EDOM; | ||
278 | } | ||
279 | if(copy_from_user(dma_buf, &(buf)[p], l)) | ||
280 | return -EFAULT; | ||
281 | } | ||
282 | else audio_devs[dev]->d->copy_user (dev, | ||
283 | dma_buf, 0, | ||
284 | buf, p, | ||
285 | c, buf_size, | ||
286 | &used, &returned, | ||
287 | l); | ||
288 | l = returned; | ||
289 | |||
290 | if (audio_devs[dev]->local_conversion & CNV_MU_LAW) | ||
291 | { | ||
292 | translate_bytes(ulaw_dsp, (unsigned char *) dma_buf, l); | ||
293 | } | ||
294 | c -= used; | ||
295 | p += used; | ||
296 | DMAbuf_move_wrpointer(dev, l); | ||
297 | |||
298 | } | ||
299 | |||
300 | return count; | ||
301 | } | ||
302 | |||
303 | int audio_read(int dev, struct file *file, char __user *buf, int count) | ||
304 | { | ||
305 | int c, p, l; | ||
306 | char *dmabuf; | ||
307 | int buf_no; | ||
308 | |||
309 | dev = dev >> 4; | ||
310 | p = 0; | ||
311 | c = count; | ||
312 | |||
313 | if (!(audio_devs[dev]->open_mode & OPEN_READ)) | ||
314 | return -EPERM; | ||
315 | |||
316 | if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) | ||
317 | sync_output(dev); | ||
318 | |||
319 | if (audio_devs[dev]->flags & DMA_DUPLEX) | ||
320 | audio_devs[dev]->audio_mode |= AM_READ; | ||
321 | else | ||
322 | audio_devs[dev]->audio_mode = AM_READ; | ||
323 | |||
324 | while(c) | ||
325 | { | ||
326 | if ((buf_no = DMAbuf_getrdbuffer(dev, &dmabuf, &l, !!(file->f_flags & O_NONBLOCK))) < 0) | ||
327 | { | ||
328 | /* | ||
329 | * Nonblocking mode handling. Return current # of bytes | ||
330 | */ | ||
331 | |||
332 | if (p > 0) /* Avoid throwing away data */ | ||
333 | return p; /* Return it instead */ | ||
334 | |||
335 | if ((file->f_flags & O_NONBLOCK) && buf_no == -EAGAIN) | ||
336 | return -EAGAIN; | ||
337 | |||
338 | return buf_no; | ||
339 | } | ||
340 | if (l > c) | ||
341 | l = c; | ||
342 | |||
343 | /* | ||
344 | * Insert any local processing here. | ||
345 | */ | ||
346 | |||
347 | if (audio_devs[dev]->local_conversion & CNV_MU_LAW) | ||
348 | { | ||
349 | translate_bytes(dsp_ulaw, (unsigned char *) dmabuf, l); | ||
350 | } | ||
351 | |||
352 | { | ||
353 | char *fixit = dmabuf; | ||
354 | |||
355 | if(copy_to_user(&(buf)[p], fixit, l)) | ||
356 | return -EFAULT; | ||
357 | }; | ||
358 | |||
359 | DMAbuf_rmchars(dev, buf_no, l); | ||
360 | |||
361 | p += l; | ||
362 | c -= l; | ||
363 | } | ||
364 | |||
365 | return count - c; | ||
366 | } | ||
367 | |||
368 | int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) | ||
369 | { | ||
370 | int val, count; | ||
371 | unsigned long flags; | ||
372 | struct dma_buffparms *dmap; | ||
373 | int __user *p = arg; | ||
374 | |||
375 | dev = dev >> 4; | ||
376 | |||
377 | if (_IOC_TYPE(cmd) == 'C') { | ||
378 | if (audio_devs[dev]->coproc) /* Coprocessor ioctl */ | ||
379 | return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0); | ||
380 | /* else | ||
381 | printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */ | ||
382 | return -ENXIO; | ||
383 | } | ||
384 | else switch (cmd) | ||
385 | { | ||
386 | case SNDCTL_DSP_SYNC: | ||
387 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
388 | return 0; | ||
389 | if (audio_devs[dev]->dmap_out->fragment_size == 0) | ||
390 | return 0; | ||
391 | sync_output(dev); | ||
392 | DMAbuf_sync(dev); | ||
393 | DMAbuf_reset(dev); | ||
394 | return 0; | ||
395 | |||
396 | case SNDCTL_DSP_POST: | ||
397 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
398 | return 0; | ||
399 | if (audio_devs[dev]->dmap_out->fragment_size == 0) | ||
400 | return 0; | ||
401 | audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY; | ||
402 | sync_output(dev); | ||
403 | dma_ioctl(dev, SNDCTL_DSP_POST, NULL); | ||
404 | return 0; | ||
405 | |||
406 | case SNDCTL_DSP_RESET: | ||
407 | audio_devs[dev]->audio_mode = AM_NONE; | ||
408 | DMAbuf_reset(dev); | ||
409 | return 0; | ||
410 | |||
411 | case SNDCTL_DSP_GETFMTS: | ||
412 | val = audio_devs[dev]->format_mask | AFMT_MU_LAW; | ||
413 | break; | ||
414 | |||
415 | case SNDCTL_DSP_SETFMT: | ||
416 | if (get_user(val, p)) | ||
417 | return -EFAULT; | ||
418 | val = set_format(dev, val); | ||
419 | break; | ||
420 | |||
421 | case SNDCTL_DSP_GETISPACE: | ||
422 | if (!(audio_devs[dev]->open_mode & OPEN_READ)) | ||
423 | return 0; | ||
424 | if ((audio_devs[dev]->audio_mode & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) | ||
425 | return -EBUSY; | ||
426 | return dma_ioctl(dev, cmd, arg); | ||
427 | |||
428 | case SNDCTL_DSP_GETOSPACE: | ||
429 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
430 | return -EPERM; | ||
431 | if ((audio_devs[dev]->audio_mode & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) | ||
432 | return -EBUSY; | ||
433 | return dma_ioctl(dev, cmd, arg); | ||
434 | |||
435 | case SNDCTL_DSP_NONBLOCK: | ||
436 | file->f_flags |= O_NONBLOCK; | ||
437 | return 0; | ||
438 | |||
439 | case SNDCTL_DSP_GETCAPS: | ||
440 | val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ | ||
441 | if (audio_devs[dev]->flags & DMA_DUPLEX && | ||
442 | audio_devs[dev]->open_mode == OPEN_READWRITE) | ||
443 | val |= DSP_CAP_DUPLEX; | ||
444 | if (audio_devs[dev]->coproc) | ||
445 | val |= DSP_CAP_COPROC; | ||
446 | if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ | ||
447 | val |= DSP_CAP_BATCH; | ||
448 | if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ | ||
449 | val |= DSP_CAP_TRIGGER; | ||
450 | break; | ||
451 | |||
452 | case SOUND_PCM_WRITE_RATE: | ||
453 | if (get_user(val, p)) | ||
454 | return -EFAULT; | ||
455 | val = audio_devs[dev]->d->set_speed(dev, val); | ||
456 | break; | ||
457 | |||
458 | case SOUND_PCM_READ_RATE: | ||
459 | val = audio_devs[dev]->d->set_speed(dev, 0); | ||
460 | break; | ||
461 | |||
462 | case SNDCTL_DSP_STEREO: | ||
463 | if (get_user(val, p)) | ||
464 | return -EFAULT; | ||
465 | if (val > 1 || val < 0) | ||
466 | return -EINVAL; | ||
467 | val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; | ||
468 | break; | ||
469 | |||
470 | case SOUND_PCM_WRITE_CHANNELS: | ||
471 | if (get_user(val, p)) | ||
472 | return -EFAULT; | ||
473 | val = audio_devs[dev]->d->set_channels(dev, val); | ||
474 | break; | ||
475 | |||
476 | case SOUND_PCM_READ_CHANNELS: | ||
477 | val = audio_devs[dev]->d->set_channels(dev, 0); | ||
478 | break; | ||
479 | |||
480 | case SOUND_PCM_READ_BITS: | ||
481 | val = audio_devs[dev]->d->set_bits(dev, 0); | ||
482 | break; | ||
483 | |||
484 | case SNDCTL_DSP_SETDUPLEX: | ||
485 | if (audio_devs[dev]->open_mode != OPEN_READWRITE) | ||
486 | return -EPERM; | ||
487 | return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; | ||
488 | |||
489 | case SNDCTL_DSP_PROFILE: | ||
490 | if (get_user(val, p)) | ||
491 | return -EFAULT; | ||
492 | if (audio_devs[dev]->open_mode & OPEN_WRITE) | ||
493 | audio_devs[dev]->dmap_out->applic_profile = val; | ||
494 | if (audio_devs[dev]->open_mode & OPEN_READ) | ||
495 | audio_devs[dev]->dmap_in->applic_profile = val; | ||
496 | return 0; | ||
497 | |||
498 | case SNDCTL_DSP_GETODELAY: | ||
499 | dmap = audio_devs[dev]->dmap_out; | ||
500 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
501 | return -EINVAL; | ||
502 | if (!(dmap->flags & DMA_ALLOC_DONE)) | ||
503 | { | ||
504 | val=0; | ||
505 | break; | ||
506 | } | ||
507 | |||
508 | spin_lock_irqsave(&dmap->lock,flags); | ||
509 | /* Compute number of bytes that have been played */ | ||
510 | count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); | ||
511 | if (count < dmap->fragment_size && dmap->qhead != 0) | ||
512 | count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ | ||
513 | count += dmap->byte_counter; | ||
514 | |||
515 | /* Substract current count from the number of bytes written by app */ | ||
516 | count = dmap->user_counter - count; | ||
517 | if (count < 0) | ||
518 | count = 0; | ||
519 | spin_unlock_irqrestore(&dmap->lock,flags); | ||
520 | val = count; | ||
521 | break; | ||
522 | |||
523 | default: | ||
524 | return dma_ioctl(dev, cmd, arg); | ||
525 | } | ||
526 | return put_user(val, p); | ||
527 | } | ||
528 | |||
529 | void audio_init_devices(void) | ||
530 | { | ||
531 | /* | ||
532 | * NOTE! This routine could be called several times during boot. | ||
533 | */ | ||
534 | } | ||
535 | |||
536 | void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) | ||
537 | { | ||
538 | /* | ||
539 | * This routine breaks the physical device buffers to logical ones. | ||
540 | */ | ||
541 | |||
542 | struct audio_operations *dsp_dev = audio_devs[dev]; | ||
543 | |||
544 | unsigned i, n; | ||
545 | unsigned sr, nc, sz, bsz; | ||
546 | |||
547 | sr = dsp_dev->d->set_speed(dev, 0); | ||
548 | nc = dsp_dev->d->set_channels(dev, 0); | ||
549 | sz = dsp_dev->d->set_bits(dev, 0); | ||
550 | |||
551 | if (sz == 8) | ||
552 | dmap->neutral_byte = NEUTRAL8; | ||
553 | else | ||
554 | dmap->neutral_byte = NEUTRAL16; | ||
555 | |||
556 | if (sr < 1 || nc < 1 || sz < 1) | ||
557 | { | ||
558 | /* printk(KERN_DEBUG "Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);*/ | ||
559 | sr = DSP_DEFAULT_SPEED; | ||
560 | nc = 1; | ||
561 | sz = 8; | ||
562 | } | ||
563 | |||
564 | sz = sr * nc * sz; | ||
565 | |||
566 | sz /= 8; /* #bits -> #bytes */ | ||
567 | dmap->data_rate = sz; | ||
568 | |||
569 | if (!dmap->needs_reorg) | ||
570 | return; | ||
571 | dmap->needs_reorg = 0; | ||
572 | |||
573 | if (dmap->fragment_size == 0) | ||
574 | { | ||
575 | /* Compute the fragment size using the default algorithm */ | ||
576 | |||
577 | /* | ||
578 | * Compute a buffer size for time not exceeding 1 second. | ||
579 | * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds | ||
580 | * of sound (using the current speed, sample size and #channels). | ||
581 | */ | ||
582 | |||
583 | bsz = dmap->buffsize; | ||
584 | while (bsz > sz) | ||
585 | bsz /= 2; | ||
586 | |||
587 | if (bsz == dmap->buffsize) | ||
588 | bsz /= 2; /* Needs at least 2 buffers */ | ||
589 | |||
590 | /* | ||
591 | * Split the computed fragment to smaller parts. After 3.5a9 | ||
592 | * the default subdivision is 4 which should give better | ||
593 | * results when recording. | ||
594 | */ | ||
595 | |||
596 | if (dmap->subdivision == 0) /* Not already set */ | ||
597 | { | ||
598 | dmap->subdivision = 4; /* Init to the default value */ | ||
599 | |||
600 | if ((bsz / dmap->subdivision) > 4096) | ||
601 | dmap->subdivision *= 2; | ||
602 | if ((bsz / dmap->subdivision) < 4096) | ||
603 | dmap->subdivision = 1; | ||
604 | } | ||
605 | bsz /= dmap->subdivision; | ||
606 | |||
607 | if (bsz < 16) | ||
608 | bsz = 16; /* Just a sanity check */ | ||
609 | |||
610 | dmap->fragment_size = bsz; | ||
611 | } | ||
612 | else | ||
613 | { | ||
614 | /* | ||
615 | * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or | ||
616 | * the buffer size computation has already been done. | ||
617 | */ | ||
618 | if (dmap->fragment_size > (dmap->buffsize / 2)) | ||
619 | dmap->fragment_size = (dmap->buffsize / 2); | ||
620 | bsz = dmap->fragment_size; | ||
621 | } | ||
622 | |||
623 | if (audio_devs[dev]->min_fragment) | ||
624 | if (bsz < (1 << audio_devs[dev]->min_fragment)) | ||
625 | bsz = 1 << audio_devs[dev]->min_fragment; | ||
626 | if (audio_devs[dev]->max_fragment) | ||
627 | if (bsz > (1 << audio_devs[dev]->max_fragment)) | ||
628 | bsz = 1 << audio_devs[dev]->max_fragment; | ||
629 | bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ | ||
630 | #ifdef OS_DMA_ALIGN_CHECK | ||
631 | OS_DMA_ALIGN_CHECK(bsz); | ||
632 | #endif | ||
633 | |||
634 | n = dmap->buffsize / bsz; | ||
635 | if (n > MAX_SUB_BUFFERS) | ||
636 | n = MAX_SUB_BUFFERS; | ||
637 | if (n > dmap->max_fragments) | ||
638 | n = dmap->max_fragments; | ||
639 | |||
640 | if (n < 2) | ||
641 | { | ||
642 | n = 2; | ||
643 | bsz /= 2; | ||
644 | } | ||
645 | dmap->nbufs = n; | ||
646 | dmap->bytes_in_use = n * bsz; | ||
647 | dmap->fragment_size = bsz; | ||
648 | dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + | ||
649 | dmap->bytes_in_use; /* Approximately one hour */ | ||
650 | |||
651 | if (dmap->raw_buf) | ||
652 | { | ||
653 | memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); | ||
654 | } | ||
655 | |||
656 | for (i = 0; i < dmap->nbufs; i++) | ||
657 | { | ||
658 | dmap->counts[i] = 0; | ||
659 | } | ||
660 | |||
661 | dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; | ||
662 | } | ||
663 | |||
664 | static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact) | ||
665 | { | ||
666 | if (fact == 0) | ||
667 | { | ||
668 | fact = dmap->subdivision; | ||
669 | if (fact == 0) | ||
670 | fact = 1; | ||
671 | return fact; | ||
672 | } | ||
673 | if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ | ||
674 | return -EINVAL; | ||
675 | |||
676 | if (fact > MAX_REALTIME_FACTOR) | ||
677 | return -EINVAL; | ||
678 | |||
679 | if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) | ||
680 | return -EINVAL; | ||
681 | |||
682 | dmap->subdivision = fact; | ||
683 | return fact; | ||
684 | } | ||
685 | |||
686 | static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact) | ||
687 | { | ||
688 | int bytes, count; | ||
689 | |||
690 | if (fact == 0) | ||
691 | return -EIO; | ||
692 | |||
693 | if (dmap->subdivision != 0 || | ||
694 | dmap->fragment_size) /* Too late to change */ | ||
695 | return -EINVAL; | ||
696 | |||
697 | bytes = fact & 0xffff; | ||
698 | count = (fact >> 16) & 0x7fff; | ||
699 | |||
700 | if (count == 0) | ||
701 | count = MAX_SUB_BUFFERS; | ||
702 | else if (count < MAX_SUB_BUFFERS) | ||
703 | count++; | ||
704 | |||
705 | if (bytes < 4 || bytes > 17) /* <16 || > 512k */ | ||
706 | return -EINVAL; | ||
707 | |||
708 | if (count < 2) | ||
709 | return -EINVAL; | ||
710 | |||
711 | if (audio_devs[dev]->min_fragment > 0) | ||
712 | if (bytes < audio_devs[dev]->min_fragment) | ||
713 | bytes = audio_devs[dev]->min_fragment; | ||
714 | |||
715 | if (audio_devs[dev]->max_fragment > 0) | ||
716 | if (bytes > audio_devs[dev]->max_fragment) | ||
717 | bytes = audio_devs[dev]->max_fragment; | ||
718 | |||
719 | #ifdef OS_DMA_MINBITS | ||
720 | if (bytes < OS_DMA_MINBITS) | ||
721 | bytes = OS_DMA_MINBITS; | ||
722 | #endif | ||
723 | |||
724 | dmap->fragment_size = (1 << bytes); | ||
725 | dmap->max_fragments = count; | ||
726 | |||
727 | if (dmap->fragment_size > dmap->buffsize) | ||
728 | dmap->fragment_size = dmap->buffsize; | ||
729 | |||
730 | if (dmap->fragment_size == dmap->buffsize && | ||
731 | audio_devs[dev]->flags & DMA_AUTOMODE) | ||
732 | dmap->fragment_size /= 2; /* Needs at least 2 buffers */ | ||
733 | |||
734 | dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ | ||
735 | return bytes | ((count - 1) << 16); | ||
736 | } | ||
737 | |||
738 | static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) | ||
739 | { | ||
740 | struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; | ||
741 | struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; | ||
742 | struct dma_buffparms *dmap; | ||
743 | audio_buf_info info; | ||
744 | count_info cinfo; | ||
745 | int fact, ret, changed, bits, count, err; | ||
746 | unsigned long flags; | ||
747 | |||
748 | switch (cmd) | ||
749 | { | ||
750 | case SNDCTL_DSP_SUBDIVIDE: | ||
751 | ret = 0; | ||
752 | if (get_user(fact, (int __user *)arg)) | ||
753 | return -EFAULT; | ||
754 | if (audio_devs[dev]->open_mode & OPEN_WRITE) | ||
755 | ret = dma_subdivide(dev, dmap_out, fact); | ||
756 | if (ret < 0) | ||
757 | return ret; | ||
758 | if (audio_devs[dev]->open_mode != OPEN_WRITE || | ||
759 | (audio_devs[dev]->flags & DMA_DUPLEX && | ||
760 | audio_devs[dev]->open_mode & OPEN_READ)) | ||
761 | ret = dma_subdivide(dev, dmap_in, fact); | ||
762 | if (ret < 0) | ||
763 | return ret; | ||
764 | break; | ||
765 | |||
766 | case SNDCTL_DSP_GETISPACE: | ||
767 | case SNDCTL_DSP_GETOSPACE: | ||
768 | dmap = dmap_out; | ||
769 | if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ)) | ||
770 | return -EINVAL; | ||
771 | if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
772 | return -EINVAL; | ||
773 | if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) | ||
774 | dmap = dmap_in; | ||
775 | if (dmap->mapping_flags & DMA_MAP_MAPPED) | ||
776 | return -EINVAL; | ||
777 | if (!(dmap->flags & DMA_ALLOC_DONE)) | ||
778 | reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); | ||
779 | info.fragstotal = dmap->nbufs; | ||
780 | if (cmd == SNDCTL_DSP_GETISPACE) | ||
781 | info.fragments = dmap->qlen; | ||
782 | else | ||
783 | { | ||
784 | if (!DMAbuf_space_in_queue(dev)) | ||
785 | info.fragments = 0; | ||
786 | else | ||
787 | { | ||
788 | info.fragments = DMAbuf_space_in_queue(dev); | ||
789 | if (audio_devs[dev]->d->local_qlen) | ||
790 | { | ||
791 | int tmp = audio_devs[dev]->d->local_qlen(dev); | ||
792 | if (tmp && info.fragments) | ||
793 | tmp--; /* | ||
794 | * This buffer has been counted twice | ||
795 | */ | ||
796 | info.fragments -= tmp; | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | if (info.fragments < 0) | ||
801 | info.fragments = 0; | ||
802 | else if (info.fragments > dmap->nbufs) | ||
803 | info.fragments = dmap->nbufs; | ||
804 | |||
805 | info.fragsize = dmap->fragment_size; | ||
806 | info.bytes = info.fragments * dmap->fragment_size; | ||
807 | |||
808 | if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) | ||
809 | info.bytes -= dmap->counts[dmap->qhead]; | ||
810 | else | ||
811 | { | ||
812 | info.fragments = info.bytes / dmap->fragment_size; | ||
813 | info.bytes -= dmap->user_counter % dmap->fragment_size; | ||
814 | } | ||
815 | if (copy_to_user(arg, &info, sizeof(info))) | ||
816 | return -EFAULT; | ||
817 | return 0; | ||
818 | |||
819 | case SNDCTL_DSP_SETTRIGGER: | ||
820 | if (get_user(bits, (int __user *)arg)) | ||
821 | return -EFAULT; | ||
822 | bits &= audio_devs[dev]->open_mode; | ||
823 | if (audio_devs[dev]->d->trigger == NULL) | ||
824 | return -EINVAL; | ||
825 | if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && | ||
826 | (bits & PCM_ENABLE_OUTPUT)) | ||
827 | return -EINVAL; | ||
828 | |||
829 | if (bits & PCM_ENABLE_INPUT) | ||
830 | { | ||
831 | spin_lock_irqsave(&dmap_in->lock,flags); | ||
832 | changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_INPUT; | ||
833 | if (changed && audio_devs[dev]->go) | ||
834 | { | ||
835 | reorganize_buffers(dev, dmap_in, 1); | ||
836 | if ((err = audio_devs[dev]->d->prepare_for_input(dev, | ||
837 | dmap_in->fragment_size, dmap_in->nbufs)) < 0) { | ||
838 | spin_unlock_irqrestore(&dmap_in->lock,flags); | ||
839 | return -err; | ||
840 | } | ||
841 | dmap_in->dma_mode = DMODE_INPUT; | ||
842 | audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; | ||
843 | DMAbuf_activate_recording(dev, dmap_in); | ||
844 | } else | ||
845 | audio_devs[dev]->enable_bits &= ~PCM_ENABLE_INPUT; | ||
846 | spin_unlock_irqrestore(&dmap_in->lock,flags); | ||
847 | } | ||
848 | if (bits & PCM_ENABLE_OUTPUT) | ||
849 | { | ||
850 | spin_lock_irqsave(&dmap_out->lock,flags); | ||
851 | changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_OUTPUT; | ||
852 | if (changed && | ||
853 | (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && | ||
854 | audio_devs[dev]->go) | ||
855 | { | ||
856 | if (!(dmap_out->flags & DMA_ALLOC_DONE)) | ||
857 | reorganize_buffers(dev, dmap_out, 0); | ||
858 | dmap_out->dma_mode = DMODE_OUTPUT; | ||
859 | audio_devs[dev]->enable_bits |= PCM_ENABLE_OUTPUT; | ||
860 | dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; | ||
861 | DMAbuf_launch_output(dev, dmap_out); | ||
862 | } else | ||
863 | audio_devs[dev]->enable_bits &= ~PCM_ENABLE_OUTPUT; | ||
864 | spin_unlock_irqrestore(&dmap_out->lock,flags); | ||
865 | } | ||
866 | #if 0 | ||
867 | if (changed && audio_devs[dev]->d->trigger) | ||
868 | audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); | ||
869 | #endif | ||
870 | /* Falls through... */ | ||
871 | |||
872 | case SNDCTL_DSP_GETTRIGGER: | ||
873 | ret = audio_devs[dev]->enable_bits; | ||
874 | break; | ||
875 | |||
876 | case SNDCTL_DSP_SETSYNCRO: | ||
877 | if (!audio_devs[dev]->d->trigger) | ||
878 | return -EINVAL; | ||
879 | audio_devs[dev]->d->trigger(dev, 0); | ||
880 | audio_devs[dev]->go = 0; | ||
881 | return 0; | ||
882 | |||
883 | case SNDCTL_DSP_GETIPTR: | ||
884 | if (!(audio_devs[dev]->open_mode & OPEN_READ)) | ||
885 | return -EINVAL; | ||
886 | spin_lock_irqsave(&dmap_in->lock,flags); | ||
887 | cinfo.bytes = dmap_in->byte_counter; | ||
888 | cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; | ||
889 | if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) | ||
890 | cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */ | ||
891 | cinfo.blocks = dmap_in->qlen; | ||
892 | cinfo.bytes += cinfo.ptr; | ||
893 | if (dmap_in->mapping_flags & DMA_MAP_MAPPED) | ||
894 | dmap_in->qlen = 0; /* Reset interrupt counter */ | ||
895 | spin_unlock_irqrestore(&dmap_in->lock,flags); | ||
896 | if (copy_to_user(arg, &cinfo, sizeof(cinfo))) | ||
897 | return -EFAULT; | ||
898 | return 0; | ||
899 | |||
900 | case SNDCTL_DSP_GETOPTR: | ||
901 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
902 | return -EINVAL; | ||
903 | |||
904 | spin_lock_irqsave(&dmap_out->lock,flags); | ||
905 | cinfo.bytes = dmap_out->byte_counter; | ||
906 | cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; | ||
907 | if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) | ||
908 | cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ | ||
909 | cinfo.blocks = dmap_out->qlen; | ||
910 | cinfo.bytes += cinfo.ptr; | ||
911 | if (dmap_out->mapping_flags & DMA_MAP_MAPPED) | ||
912 | dmap_out->qlen = 0; /* Reset interrupt counter */ | ||
913 | spin_unlock_irqrestore(&dmap_out->lock,flags); | ||
914 | if (copy_to_user(arg, &cinfo, sizeof(cinfo))) | ||
915 | return -EFAULT; | ||
916 | return 0; | ||
917 | |||
918 | case SNDCTL_DSP_GETODELAY: | ||
919 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) | ||
920 | return -EINVAL; | ||
921 | if (!(dmap_out->flags & DMA_ALLOC_DONE)) | ||
922 | { | ||
923 | ret=0; | ||
924 | break; | ||
925 | } | ||
926 | spin_lock_irqsave(&dmap_out->lock,flags); | ||
927 | /* Compute number of bytes that have been played */ | ||
928 | count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); | ||
929 | if (count < dmap_out->fragment_size && dmap_out->qhead != 0) | ||
930 | count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ | ||
931 | count += dmap_out->byte_counter; | ||
932 | /* Substract current count from the number of bytes written by app */ | ||
933 | count = dmap_out->user_counter - count; | ||
934 | if (count < 0) | ||
935 | count = 0; | ||
936 | spin_unlock_irqrestore(&dmap_out->lock,flags); | ||
937 | ret = count; | ||
938 | break; | ||
939 | |||
940 | case SNDCTL_DSP_POST: | ||
941 | if (audio_devs[dev]->dmap_out->qlen > 0) | ||
942 | if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) | ||
943 | DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); | ||
944 | return 0; | ||
945 | |||
946 | case SNDCTL_DSP_GETBLKSIZE: | ||
947 | dmap = dmap_out; | ||
948 | if (audio_devs[dev]->open_mode & OPEN_WRITE) | ||
949 | reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); | ||
950 | if (audio_devs[dev]->open_mode == OPEN_READ || | ||
951 | (audio_devs[dev]->flags & DMA_DUPLEX && | ||
952 | audio_devs[dev]->open_mode & OPEN_READ)) | ||
953 | reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); | ||
954 | if (audio_devs[dev]->open_mode == OPEN_READ) | ||
955 | dmap = dmap_in; | ||
956 | ret = dmap->fragment_size; | ||
957 | break; | ||
958 | |||
959 | case SNDCTL_DSP_SETFRAGMENT: | ||
960 | ret = 0; | ||
961 | if (get_user(fact, (int __user *)arg)) | ||
962 | return -EFAULT; | ||
963 | if (audio_devs[dev]->open_mode & OPEN_WRITE) | ||
964 | ret = dma_set_fragment(dev, dmap_out, fact); | ||
965 | if (ret < 0) | ||
966 | return ret; | ||
967 | if (audio_devs[dev]->open_mode == OPEN_READ || | ||
968 | (audio_devs[dev]->flags & DMA_DUPLEX && | ||
969 | audio_devs[dev]->open_mode & OPEN_READ)) | ||
970 | ret = dma_set_fragment(dev, dmap_in, fact); | ||
971 | if (ret < 0) | ||
972 | return ret; | ||
973 | if (!arg) /* don't know what this is good for, but preserve old semantics */ | ||
974 | return 0; | ||
975 | break; | ||
976 | |||
977 | default: | ||
978 | if (!audio_devs[dev]->d->ioctl) | ||
979 | return -EINVAL; | ||
980 | return audio_devs[dev]->d->ioctl(dev, cmd, arg); | ||
981 | } | ||
982 | return put_user(ret, (int __user *)arg); | ||
983 | } | ||