Root/
1 | /* |
2 | * sound/oss/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 | spin_lock(&file->f_lock); |
437 | file->f_flags |= O_NONBLOCK; |
438 | spin_unlock(&file->f_lock); |
439 | return 0; |
440 | |
441 | case SNDCTL_DSP_GETCAPS: |
442 | val = 1 | DSP_CAP_MMAP; /* Revision level of this ioctl() */ |
443 | if (audio_devs[dev]->flags & DMA_DUPLEX && |
444 | audio_devs[dev]->open_mode == OPEN_READWRITE) |
445 | val |= DSP_CAP_DUPLEX; |
446 | if (audio_devs[dev]->coproc) |
447 | val |= DSP_CAP_COPROC; |
448 | if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ |
449 | val |= DSP_CAP_BATCH; |
450 | if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ |
451 | val |= DSP_CAP_TRIGGER; |
452 | break; |
453 | |
454 | case SOUND_PCM_WRITE_RATE: |
455 | if (get_user(val, p)) |
456 | return -EFAULT; |
457 | val = audio_devs[dev]->d->set_speed(dev, val); |
458 | break; |
459 | |
460 | case SOUND_PCM_READ_RATE: |
461 | val = audio_devs[dev]->d->set_speed(dev, 0); |
462 | break; |
463 | |
464 | case SNDCTL_DSP_STEREO: |
465 | if (get_user(val, p)) |
466 | return -EFAULT; |
467 | if (val > 1 || val < 0) |
468 | return -EINVAL; |
469 | val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1; |
470 | break; |
471 | |
472 | case SOUND_PCM_WRITE_CHANNELS: |
473 | if (get_user(val, p)) |
474 | return -EFAULT; |
475 | val = audio_devs[dev]->d->set_channels(dev, val); |
476 | break; |
477 | |
478 | case SOUND_PCM_READ_CHANNELS: |
479 | val = audio_devs[dev]->d->set_channels(dev, 0); |
480 | break; |
481 | |
482 | case SOUND_PCM_READ_BITS: |
483 | val = audio_devs[dev]->d->set_bits(dev, 0); |
484 | break; |
485 | |
486 | case SNDCTL_DSP_SETDUPLEX: |
487 | if (audio_devs[dev]->open_mode != OPEN_READWRITE) |
488 | return -EPERM; |
489 | return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO; |
490 | |
491 | case SNDCTL_DSP_PROFILE: |
492 | if (get_user(val, p)) |
493 | return -EFAULT; |
494 | if (audio_devs[dev]->open_mode & OPEN_WRITE) |
495 | audio_devs[dev]->dmap_out->applic_profile = val; |
496 | if (audio_devs[dev]->open_mode & OPEN_READ) |
497 | audio_devs[dev]->dmap_in->applic_profile = val; |
498 | return 0; |
499 | |
500 | case SNDCTL_DSP_GETODELAY: |
501 | dmap = audio_devs[dev]->dmap_out; |
502 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) |
503 | return -EINVAL; |
504 | if (!(dmap->flags & DMA_ALLOC_DONE)) |
505 | { |
506 | val=0; |
507 | break; |
508 | } |
509 | |
510 | spin_lock_irqsave(&dmap->lock,flags); |
511 | /* Compute number of bytes that have been played */ |
512 | count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT); |
513 | if (count < dmap->fragment_size && dmap->qhead != 0) |
514 | count += dmap->bytes_in_use; /* Pointer wrap not handled yet */ |
515 | count += dmap->byte_counter; |
516 | |
517 | /* Subtract current count from the number of bytes written by app */ |
518 | count = dmap->user_counter - count; |
519 | if (count < 0) |
520 | count = 0; |
521 | spin_unlock_irqrestore(&dmap->lock,flags); |
522 | val = count; |
523 | break; |
524 | |
525 | default: |
526 | return dma_ioctl(dev, cmd, arg); |
527 | } |
528 | return put_user(val, p); |
529 | } |
530 | |
531 | void audio_init_devices(void) |
532 | { |
533 | /* |
534 | * NOTE! This routine could be called several times during boot. |
535 | */ |
536 | } |
537 | |
538 | void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording) |
539 | { |
540 | /* |
541 | * This routine breaks the physical device buffers to logical ones. |
542 | */ |
543 | |
544 | struct audio_operations *dsp_dev = audio_devs[dev]; |
545 | |
546 | unsigned i, n; |
547 | unsigned sr, nc, sz, bsz; |
548 | |
549 | sr = dsp_dev->d->set_speed(dev, 0); |
550 | nc = dsp_dev->d->set_channels(dev, 0); |
551 | sz = dsp_dev->d->set_bits(dev, 0); |
552 | |
553 | if (sz == 8) |
554 | dmap->neutral_byte = NEUTRAL8; |
555 | else |
556 | dmap->neutral_byte = NEUTRAL16; |
557 | |
558 | if (sr < 1 || nc < 1 || sz < 1) |
559 | { |
560 | /* printk(KERN_DEBUG "Warning: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz);*/ |
561 | sr = DSP_DEFAULT_SPEED; |
562 | nc = 1; |
563 | sz = 8; |
564 | } |
565 | |
566 | sz = sr * nc * sz; |
567 | |
568 | sz /= 8; /* #bits -> #bytes */ |
569 | dmap->data_rate = sz; |
570 | |
571 | if (!dmap->needs_reorg) |
572 | return; |
573 | dmap->needs_reorg = 0; |
574 | |
575 | if (dmap->fragment_size == 0) |
576 | { |
577 | /* Compute the fragment size using the default algorithm */ |
578 | |
579 | /* |
580 | * Compute a buffer size for time not exceeding 1 second. |
581 | * Usually this algorithm gives a buffer size for 0.5 to 1.0 seconds |
582 | * of sound (using the current speed, sample size and #channels). |
583 | */ |
584 | |
585 | bsz = dmap->buffsize; |
586 | while (bsz > sz) |
587 | bsz /= 2; |
588 | |
589 | if (bsz == dmap->buffsize) |
590 | bsz /= 2; /* Needs at least 2 buffers */ |
591 | |
592 | /* |
593 | * Split the computed fragment to smaller parts. After 3.5a9 |
594 | * the default subdivision is 4 which should give better |
595 | * results when recording. |
596 | */ |
597 | |
598 | if (dmap->subdivision == 0) /* Not already set */ |
599 | { |
600 | dmap->subdivision = 4; /* Init to the default value */ |
601 | |
602 | if ((bsz / dmap->subdivision) > 4096) |
603 | dmap->subdivision *= 2; |
604 | if ((bsz / dmap->subdivision) < 4096) |
605 | dmap->subdivision = 1; |
606 | } |
607 | bsz /= dmap->subdivision; |
608 | |
609 | if (bsz < 16) |
610 | bsz = 16; /* Just a sanity check */ |
611 | |
612 | dmap->fragment_size = bsz; |
613 | } |
614 | else |
615 | { |
616 | /* |
617 | * The process has specified the buffer size with SNDCTL_DSP_SETFRAGMENT or |
618 | * the buffer size computation has already been done. |
619 | */ |
620 | if (dmap->fragment_size > (dmap->buffsize / 2)) |
621 | dmap->fragment_size = (dmap->buffsize / 2); |
622 | bsz = dmap->fragment_size; |
623 | } |
624 | |
625 | if (audio_devs[dev]->min_fragment) |
626 | if (bsz < (1 << audio_devs[dev]->min_fragment)) |
627 | bsz = 1 << audio_devs[dev]->min_fragment; |
628 | if (audio_devs[dev]->max_fragment) |
629 | if (bsz > (1 << audio_devs[dev]->max_fragment)) |
630 | bsz = 1 << audio_devs[dev]->max_fragment; |
631 | bsz &= ~0x07; /* Force size which is multiple of 8 bytes */ |
632 | #ifdef OS_DMA_ALIGN_CHECK |
633 | OS_DMA_ALIGN_CHECK(bsz); |
634 | #endif |
635 | |
636 | n = dmap->buffsize / bsz; |
637 | if (n > MAX_SUB_BUFFERS) |
638 | n = MAX_SUB_BUFFERS; |
639 | if (n > dmap->max_fragments) |
640 | n = dmap->max_fragments; |
641 | |
642 | if (n < 2) |
643 | { |
644 | n = 2; |
645 | bsz /= 2; |
646 | } |
647 | dmap->nbufs = n; |
648 | dmap->bytes_in_use = n * bsz; |
649 | dmap->fragment_size = bsz; |
650 | dmap->max_byte_counter = (dmap->data_rate * 60 * 60) + |
651 | dmap->bytes_in_use; /* Approximately one hour */ |
652 | |
653 | if (dmap->raw_buf) |
654 | { |
655 | memset(dmap->raw_buf, dmap->neutral_byte, dmap->bytes_in_use); |
656 | } |
657 | |
658 | for (i = 0; i < dmap->nbufs; i++) |
659 | { |
660 | dmap->counts[i] = 0; |
661 | } |
662 | |
663 | dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY; |
664 | } |
665 | |
666 | static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact) |
667 | { |
668 | if (fact == 0) |
669 | { |
670 | fact = dmap->subdivision; |
671 | if (fact == 0) |
672 | fact = 1; |
673 | return fact; |
674 | } |
675 | if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ |
676 | return -EINVAL; |
677 | |
678 | if (fact > MAX_REALTIME_FACTOR) |
679 | return -EINVAL; |
680 | |
681 | if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) |
682 | return -EINVAL; |
683 | |
684 | dmap->subdivision = fact; |
685 | return fact; |
686 | } |
687 | |
688 | static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact) |
689 | { |
690 | int bytes, count; |
691 | |
692 | if (fact == 0) |
693 | return -EIO; |
694 | |
695 | if (dmap->subdivision != 0 || |
696 | dmap->fragment_size) /* Too late to change */ |
697 | return -EINVAL; |
698 | |
699 | bytes = fact & 0xffff; |
700 | count = (fact >> 16) & 0x7fff; |
701 | |
702 | if (count == 0) |
703 | count = MAX_SUB_BUFFERS; |
704 | else if (count < MAX_SUB_BUFFERS) |
705 | count++; |
706 | |
707 | if (bytes < 4 || bytes > 17) /* <16 || > 512k */ |
708 | return -EINVAL; |
709 | |
710 | if (count < 2) |
711 | return -EINVAL; |
712 | |
713 | if (audio_devs[dev]->min_fragment > 0) |
714 | if (bytes < audio_devs[dev]->min_fragment) |
715 | bytes = audio_devs[dev]->min_fragment; |
716 | |
717 | if (audio_devs[dev]->max_fragment > 0) |
718 | if (bytes > audio_devs[dev]->max_fragment) |
719 | bytes = audio_devs[dev]->max_fragment; |
720 | |
721 | #ifdef OS_DMA_MINBITS |
722 | if (bytes < OS_DMA_MINBITS) |
723 | bytes = OS_DMA_MINBITS; |
724 | #endif |
725 | |
726 | dmap->fragment_size = (1 << bytes); |
727 | dmap->max_fragments = count; |
728 | |
729 | if (dmap->fragment_size > dmap->buffsize) |
730 | dmap->fragment_size = dmap->buffsize; |
731 | |
732 | if (dmap->fragment_size == dmap->buffsize && |
733 | audio_devs[dev]->flags & DMA_AUTOMODE) |
734 | dmap->fragment_size /= 2; /* Needs at least 2 buffers */ |
735 | |
736 | dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ |
737 | return bytes | ((count - 1) << 16); |
738 | } |
739 | |
740 | static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) |
741 | { |
742 | struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; |
743 | struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; |
744 | struct dma_buffparms *dmap; |
745 | audio_buf_info info; |
746 | count_info cinfo; |
747 | int fact, ret, changed, bits, count, err; |
748 | unsigned long flags; |
749 | |
750 | switch (cmd) |
751 | { |
752 | case SNDCTL_DSP_SUBDIVIDE: |
753 | ret = 0; |
754 | if (get_user(fact, (int __user *)arg)) |
755 | return -EFAULT; |
756 | if (audio_devs[dev]->open_mode & OPEN_WRITE) |
757 | ret = dma_subdivide(dev, dmap_out, fact); |
758 | if (ret < 0) |
759 | return ret; |
760 | if (audio_devs[dev]->open_mode != OPEN_WRITE || |
761 | (audio_devs[dev]->flags & DMA_DUPLEX && |
762 | audio_devs[dev]->open_mode & OPEN_READ)) |
763 | ret = dma_subdivide(dev, dmap_in, fact); |
764 | if (ret < 0) |
765 | return ret; |
766 | break; |
767 | |
768 | case SNDCTL_DSP_GETISPACE: |
769 | case SNDCTL_DSP_GETOSPACE: |
770 | dmap = dmap_out; |
771 | if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ)) |
772 | return -EINVAL; |
773 | if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE)) |
774 | return -EINVAL; |
775 | if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) |
776 | dmap = dmap_in; |
777 | if (dmap->mapping_flags & DMA_MAP_MAPPED) |
778 | return -EINVAL; |
779 | if (!(dmap->flags & DMA_ALLOC_DONE)) |
780 | reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); |
781 | info.fragstotal = dmap->nbufs; |
782 | if (cmd == SNDCTL_DSP_GETISPACE) |
783 | info.fragments = dmap->qlen; |
784 | else |
785 | { |
786 | if (!DMAbuf_space_in_queue(dev)) |
787 | info.fragments = 0; |
788 | else |
789 | { |
790 | info.fragments = DMAbuf_space_in_queue(dev); |
791 | if (audio_devs[dev]->d->local_qlen) |
792 | { |
793 | int tmp = audio_devs[dev]->d->local_qlen(dev); |
794 | if (tmp && info.fragments) |
795 | tmp--; /* |
796 | * This buffer has been counted twice |
797 | */ |
798 | info.fragments -= tmp; |
799 | } |
800 | } |
801 | } |
802 | if (info.fragments < 0) |
803 | info.fragments = 0; |
804 | else if (info.fragments > dmap->nbufs) |
805 | info.fragments = dmap->nbufs; |
806 | |
807 | info.fragsize = dmap->fragment_size; |
808 | info.bytes = info.fragments * dmap->fragment_size; |
809 | |
810 | if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen) |
811 | info.bytes -= dmap->counts[dmap->qhead]; |
812 | else |
813 | { |
814 | info.fragments = info.bytes / dmap->fragment_size; |
815 | info.bytes -= dmap->user_counter % dmap->fragment_size; |
816 | } |
817 | if (copy_to_user(arg, &info, sizeof(info))) |
818 | return -EFAULT; |
819 | return 0; |
820 | |
821 | case SNDCTL_DSP_SETTRIGGER: |
822 | if (get_user(bits, (int __user *)arg)) |
823 | return -EFAULT; |
824 | bits &= audio_devs[dev]->open_mode; |
825 | if (audio_devs[dev]->d->trigger == NULL) |
826 | return -EINVAL; |
827 | if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) && |
828 | (bits & PCM_ENABLE_OUTPUT)) |
829 | return -EINVAL; |
830 | |
831 | if (bits & PCM_ENABLE_INPUT) |
832 | { |
833 | spin_lock_irqsave(&dmap_in->lock,flags); |
834 | changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_INPUT; |
835 | if (changed && audio_devs[dev]->go) |
836 | { |
837 | reorganize_buffers(dev, dmap_in, 1); |
838 | if ((err = audio_devs[dev]->d->prepare_for_input(dev, |
839 | dmap_in->fragment_size, dmap_in->nbufs)) < 0) { |
840 | spin_unlock_irqrestore(&dmap_in->lock,flags); |
841 | return err; |
842 | } |
843 | dmap_in->dma_mode = DMODE_INPUT; |
844 | audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; |
845 | DMAbuf_activate_recording(dev, dmap_in); |
846 | } else |
847 | audio_devs[dev]->enable_bits &= ~PCM_ENABLE_INPUT; |
848 | spin_unlock_irqrestore(&dmap_in->lock,flags); |
849 | } |
850 | if (bits & PCM_ENABLE_OUTPUT) |
851 | { |
852 | spin_lock_irqsave(&dmap_out->lock,flags); |
853 | changed = (audio_devs[dev]->enable_bits ^ bits) & PCM_ENABLE_OUTPUT; |
854 | if (changed && |
855 | (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) && |
856 | audio_devs[dev]->go) |
857 | { |
858 | if (!(dmap_out->flags & DMA_ALLOC_DONE)) |
859 | reorganize_buffers(dev, dmap_out, 0); |
860 | dmap_out->dma_mode = DMODE_OUTPUT; |
861 | audio_devs[dev]->enable_bits |= PCM_ENABLE_OUTPUT; |
862 | dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; |
863 | DMAbuf_launch_output(dev, dmap_out); |
864 | } else |
865 | audio_devs[dev]->enable_bits &= ~PCM_ENABLE_OUTPUT; |
866 | spin_unlock_irqrestore(&dmap_out->lock,flags); |
867 | } |
868 | #if 0 |
869 | if (changed && audio_devs[dev]->d->trigger) |
870 | audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go); |
871 | #endif |
872 | /* Falls through... */ |
873 | |
874 | case SNDCTL_DSP_GETTRIGGER: |
875 | ret = audio_devs[dev]->enable_bits; |
876 | break; |
877 | |
878 | case SNDCTL_DSP_SETSYNCRO: |
879 | if (!audio_devs[dev]->d->trigger) |
880 | return -EINVAL; |
881 | audio_devs[dev]->d->trigger(dev, 0); |
882 | audio_devs[dev]->go = 0; |
883 | return 0; |
884 | |
885 | case SNDCTL_DSP_GETIPTR: |
886 | if (!(audio_devs[dev]->open_mode & OPEN_READ)) |
887 | return -EINVAL; |
888 | spin_lock_irqsave(&dmap_in->lock,flags); |
889 | cinfo.bytes = dmap_in->byte_counter; |
890 | cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3; |
891 | if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0) |
892 | cinfo.bytes += dmap_in->bytes_in_use; /* Pointer wrap not handled yet */ |
893 | cinfo.blocks = dmap_in->qlen; |
894 | cinfo.bytes += cinfo.ptr; |
895 | if (dmap_in->mapping_flags & DMA_MAP_MAPPED) |
896 | dmap_in->qlen = 0; /* Reset interrupt counter */ |
897 | spin_unlock_irqrestore(&dmap_in->lock,flags); |
898 | if (copy_to_user(arg, &cinfo, sizeof(cinfo))) |
899 | return -EFAULT; |
900 | return 0; |
901 | |
902 | case SNDCTL_DSP_GETOPTR: |
903 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) |
904 | return -EINVAL; |
905 | |
906 | spin_lock_irqsave(&dmap_out->lock,flags); |
907 | cinfo.bytes = dmap_out->byte_counter; |
908 | cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3; |
909 | if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0) |
910 | cinfo.bytes += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ |
911 | cinfo.blocks = dmap_out->qlen; |
912 | cinfo.bytes += cinfo.ptr; |
913 | if (dmap_out->mapping_flags & DMA_MAP_MAPPED) |
914 | dmap_out->qlen = 0; /* Reset interrupt counter */ |
915 | spin_unlock_irqrestore(&dmap_out->lock,flags); |
916 | if (copy_to_user(arg, &cinfo, sizeof(cinfo))) |
917 | return -EFAULT; |
918 | return 0; |
919 | |
920 | case SNDCTL_DSP_GETODELAY: |
921 | if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) |
922 | return -EINVAL; |
923 | if (!(dmap_out->flags & DMA_ALLOC_DONE)) |
924 | { |
925 | ret=0; |
926 | break; |
927 | } |
928 | spin_lock_irqsave(&dmap_out->lock,flags); |
929 | /* Compute number of bytes that have been played */ |
930 | count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT); |
931 | if (count < dmap_out->fragment_size && dmap_out->qhead != 0) |
932 | count += dmap_out->bytes_in_use; /* Pointer wrap not handled yet */ |
933 | count += dmap_out->byte_counter; |
934 | /* Subtract current count from the number of bytes written by app */ |
935 | count = dmap_out->user_counter - count; |
936 | if (count < 0) |
937 | count = 0; |
938 | spin_unlock_irqrestore(&dmap_out->lock,flags); |
939 | ret = count; |
940 | break; |
941 | |
942 | case SNDCTL_DSP_POST: |
943 | if (audio_devs[dev]->dmap_out->qlen > 0) |
944 | if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE)) |
945 | DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out); |
946 | return 0; |
947 | |
948 | case SNDCTL_DSP_GETBLKSIZE: |
949 | dmap = dmap_out; |
950 | if (audio_devs[dev]->open_mode & OPEN_WRITE) |
951 | reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); |
952 | if (audio_devs[dev]->open_mode == OPEN_READ || |
953 | (audio_devs[dev]->flags & DMA_DUPLEX && |
954 | audio_devs[dev]->open_mode & OPEN_READ)) |
955 | reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); |
956 | if (audio_devs[dev]->open_mode == OPEN_READ) |
957 | dmap = dmap_in; |
958 | ret = dmap->fragment_size; |
959 | break; |
960 | |
961 | case SNDCTL_DSP_SETFRAGMENT: |
962 | ret = 0; |
963 | if (get_user(fact, (int __user *)arg)) |
964 | return -EFAULT; |
965 | if (audio_devs[dev]->open_mode & OPEN_WRITE) |
966 | ret = dma_set_fragment(dev, dmap_out, fact); |
967 | if (ret < 0) |
968 | return ret; |
969 | if (audio_devs[dev]->open_mode == OPEN_READ || |
970 | (audio_devs[dev]->flags & DMA_DUPLEX && |
971 | audio_devs[dev]->open_mode & OPEN_READ)) |
972 | ret = dma_set_fragment(dev, dmap_in, fact); |
973 | if (ret < 0) |
974 | return ret; |
975 | if (!arg) /* don't know what this is good for, but preserve old semantics */ |
976 | return 0; |
977 | break; |
978 | |
979 | default: |
980 | if (!audio_devs[dev]->d->ioctl) |
981 | return -EINVAL; |
982 | return audio_devs[dev]->d->ioctl(dev, cmd, arg); |
983 | } |
984 | return put_user(ret, (int __user *)arg); |
985 | } |
986 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9