1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178#include <linux/module.h>
179#include <linux/slab.h>
180#include <linux/sound.h>
181#include <linux/init.h>
182#include <linux/soundcard.h>
183#include <linux/poll.h>
184#include <linux/mutex.h>
185#include <linux/sched/signal.h>
186
187#include <linux/uaccess.h>
188
189#include "dmasound.h"
190
191#define DMASOUND_CORE_REVISION 1
192#define DMASOUND_CORE_EDITION 6
193
194
195
196
197
198static DEFINE_MUTEX(dmasound_core_mutex);
199int dmasound_catchRadius = 0;
200module_param(dmasound_catchRadius, int, 0);
201
202static unsigned int numWriteBufs = DEFAULT_N_BUFFERS;
203module_param(numWriteBufs, int, 0);
204static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ;
205module_param(writeBufSize, int, 0);
206
207MODULE_LICENSE("GPL");
208
209#ifdef MODULE
210static int sq_unit = -1;
211static int mixer_unit = -1;
212static int state_unit = -1;
213static int irq_installed;
214#endif
215
216
217static fmode_t shared_resource_owner;
218static int shared_resources_initialised;
219
220
221
222
223
224struct sound_settings dmasound = {
225 .lock = __SPIN_LOCK_UNLOCKED(dmasound.lock)
226};
227
228static inline void sound_silence(void)
229{
230 dmasound.mach.silence();
231}
232
233static inline int sound_set_format(int format)
234{
235 return dmasound.mach.setFormat(format);
236}
237
238
239static int sound_set_speed(int speed)
240{
241 if (speed < 0)
242 return dmasound.soft.speed;
243
244
245
246
247
248
249 if (dmasound.mach.max_dsp_speed &&
250 (speed > dmasound.mach.max_dsp_speed))
251 speed = dmasound.mach.max_dsp_speed ;
252
253 dmasound.soft.speed = speed;
254
255 if (dmasound.minDev == SND_DEV_DSP)
256 dmasound.dsp.speed = dmasound.soft.speed;
257
258 return dmasound.soft.speed;
259}
260
261static int sound_set_stereo(int stereo)
262{
263 if (stereo < 0)
264 return dmasound.soft.stereo;
265
266 stereo = !!stereo;
267
268 dmasound.soft.stereo = stereo;
269 if (dmasound.minDev == SND_DEV_DSP)
270 dmasound.dsp.stereo = stereo;
271
272 return stereo;
273}
274
275static ssize_t sound_copy_translate(TRANS *trans, const u_char __user *userPtr,
276 size_t userCount, u_char frame[],
277 ssize_t *frameUsed, ssize_t frameLeft)
278{
279 ssize_t (*ct_func)(const u_char __user *, size_t, u_char *, ssize_t *, ssize_t);
280
281 switch (dmasound.soft.format) {
282 case AFMT_MU_LAW:
283 ct_func = trans->ct_ulaw;
284 break;
285 case AFMT_A_LAW:
286 ct_func = trans->ct_alaw;
287 break;
288 case AFMT_S8:
289 ct_func = trans->ct_s8;
290 break;
291 case AFMT_U8:
292 ct_func = trans->ct_u8;
293 break;
294 case AFMT_S16_BE:
295 ct_func = trans->ct_s16be;
296 break;
297 case AFMT_U16_BE:
298 ct_func = trans->ct_u16be;
299 break;
300 case AFMT_S16_LE:
301 ct_func = trans->ct_s16le;
302 break;
303 case AFMT_U16_LE:
304 ct_func = trans->ct_u16le;
305 break;
306 default:
307 return 0;
308 }
309
310
311
312 if (ct_func)
313 return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
314 return 0;
315}
316
317
318
319
320
321static struct {
322 int busy;
323 int modify_counter;
324} mixer;
325
326static int mixer_open(struct inode *inode, struct file *file)
327{
328 mutex_lock(&dmasound_core_mutex);
329 if (!try_module_get(dmasound.mach.owner)) {
330 mutex_unlock(&dmasound_core_mutex);
331 return -ENODEV;
332 }
333 mixer.busy = 1;
334 mutex_unlock(&dmasound_core_mutex);
335 return 0;
336}
337
338static int mixer_release(struct inode *inode, struct file *file)
339{
340 mutex_lock(&dmasound_core_mutex);
341 mixer.busy = 0;
342 module_put(dmasound.mach.owner);
343 mutex_unlock(&dmasound_core_mutex);
344 return 0;
345}
346
347static int mixer_ioctl(struct file *file, u_int cmd, u_long arg)
348{
349 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
350 mixer.modify_counter++;
351 switch (cmd) {
352 case OSS_GETVERSION:
353 return IOCTL_OUT(arg, SOUND_VERSION);
354 case SOUND_MIXER_INFO:
355 {
356 mixer_info info;
357 memset(&info, 0, sizeof(info));
358 strlcpy(info.id, dmasound.mach.name2, sizeof(info.id));
359 strlcpy(info.name, dmasound.mach.name2, sizeof(info.name));
360 info.modify_counter = mixer.modify_counter;
361 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
362 return -EFAULT;
363 return 0;
364 }
365 }
366 if (dmasound.mach.mixer_ioctl)
367 return dmasound.mach.mixer_ioctl(cmd, arg);
368 return -EINVAL;
369}
370
371static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
372{
373 int ret;
374
375 mutex_lock(&dmasound_core_mutex);
376 ret = mixer_ioctl(file, cmd, arg);
377 mutex_unlock(&dmasound_core_mutex);
378
379 return ret;
380}
381
382static const struct file_operations mixer_fops =
383{
384 .owner = THIS_MODULE,
385 .llseek = no_llseek,
386 .unlocked_ioctl = mixer_unlocked_ioctl,
387 .open = mixer_open,
388 .release = mixer_release,
389};
390
391static void mixer_init(void)
392{
393#ifndef MODULE
394 int mixer_unit;
395#endif
396 mixer_unit = register_sound_mixer(&mixer_fops, -1);
397 if (mixer_unit < 0)
398 return;
399
400 mixer.busy = 0;
401 dmasound.treble = 0;
402 dmasound.bass = 0;
403 if (dmasound.mach.mixer_init)
404 dmasound.mach.mixer_init();
405}
406
407
408
409
410
411
412struct sound_queue dmasound_write_sq;
413static void sq_reset_output(void) ;
414
415static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
416{
417 int i;
418
419 if (sq->buffers)
420 return 0;
421 sq->numBufs = num;
422 sq->bufSize = size;
423 sq->buffers = kmalloc_array (num, sizeof(char *), GFP_KERNEL);
424 if (!sq->buffers)
425 return -ENOMEM;
426 for (i = 0; i < num; i++) {
427 sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL);
428 if (!sq->buffers[i]) {
429 while (i--)
430 dmasound.mach.dma_free(sq->buffers[i], size);
431 kfree(sq->buffers);
432 sq->buffers = NULL;
433 return -ENOMEM;
434 }
435 }
436 return 0;
437}
438
439static void sq_release_buffers(struct sound_queue *sq)
440{
441 int i;
442
443 if (sq->buffers) {
444 for (i = 0; i < sq->numBufs; i++)
445 dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
446 kfree(sq->buffers);
447 sq->buffers = NULL;
448 }
449}
450
451
452static int sq_setup(struct sound_queue *sq)
453{
454 int (*setup_func)(void) = NULL;
455 int hard_frame ;
456
457 if (sq->locked) {
458#ifdef DEBUG_DMASOUND
459printk("dmasound_core: tried to sq_setup a locked queue\n") ;
460#endif
461 return -EINVAL ;
462 }
463 sq->locked = 1 ;
464
465
466
467
468
469 dmasound.mach.init();
470
471
472
473
474
475
476
477
478
479
480
481
482
483 if (sq->user_frags <= 0) {
484 sq->max_count = sq->numBufs ;
485 sq->max_active = sq->numBufs ;
486 sq->block_size = sq->bufSize;
487
488 sq->user_frags = sq->numBufs ;
489 sq->user_frag_size = sq->bufSize ;
490 sq->user_frag_size *=
491 (dmasound.soft.size * (dmasound.soft.stereo+1) ) ;
492 sq->user_frag_size /=
493 (dmasound.hard.size * (dmasound.hard.stereo+1) ) ;
494 } else {
495
496 sq->block_size = sq->user_frag_size ;
497 sq->block_size *=
498 (dmasound.hard.size * (dmasound.hard.stereo+1) ) ;
499 sq->block_size /=
500 (dmasound.soft.size * (dmasound.soft.stereo+1) ) ;
501
502 sq->block_size *= dmasound.hard.speed ;
503 sq->block_size /= dmasound.soft.speed ;
504
505 hard_frame =
506 (dmasound.hard.size * (dmasound.hard.stereo+1))/8 ;
507 sq->block_size += (hard_frame - 1) ;
508 sq->block_size &= ~(hard_frame - 1) ;
509
510 if ( sq->block_size <= 0 || sq->block_size > sq->bufSize) {
511#ifdef DEBUG_DMASOUND
512printk("dmasound_core: invalid frag size (user set %d)\n", sq->user_frag_size) ;
513#endif
514 sq->block_size = sq->bufSize ;
515 }
516 if ( sq->user_frags <= sq->numBufs ) {
517 sq->max_count = sq->user_frags ;
518
519 sq->max_active = (sq->max_active <= sq->max_count) ?
520 sq->max_active : sq->max_count ;
521 } else {
522#ifdef DEBUG_DMASOUND
523printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ;
524#endif
525 sq->max_count =
526 sq->max_active = sq->numBufs ;
527 }
528 }
529 sq->front = sq->count = sq->rear_size = 0;
530 sq->syncing = 0;
531 sq->active = 0;
532
533 if (sq == &write_sq) {
534 sq->rear = -1;
535 setup_func = dmasound.mach.write_sq_setup;
536 }
537 if (setup_func)
538 return setup_func();
539 return 0 ;
540}
541
542static inline void sq_play(void)
543{
544 dmasound.mach.play();
545}
546
547static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
548 loff_t *ppos)
549{
550 ssize_t uWritten = 0;
551 u_char *dest;
552 ssize_t uUsed = 0, bUsed, bLeft;
553 unsigned long flags ;
554
555
556
557
558
559 if (uLeft == 0)
560 return 0;
561
562
563
564
565
566
567 if (shared_resources_initialised == 0) {
568 dmasound.mach.init() ;
569 shared_resources_initialised = 1 ;
570 }
571
572
573
574
575
576
577
578
579 if (write_sq.locked == 0) {
580 if ((uWritten = sq_setup(&write_sq)) < 0) return uWritten ;
581 uWritten = 0 ;
582 }
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604 spin_lock_irqsave(&dmasound.lock, flags);
605 write_sq.syncing &= ~2 ;
606 spin_unlock_irqrestore(&dmasound.lock, flags);
607
608 if (write_sq.count > 0 &&
609 (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
610 dest = write_sq.buffers[write_sq.rear];
611 bUsed = write_sq.rear_size;
612 uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
613 dest, &bUsed, bLeft);
614 if (uUsed <= 0)
615 return uUsed;
616 src += uUsed;
617 uWritten += uUsed;
618 uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ;
619 write_sq.rear_size = bUsed;
620 }
621
622 while (uLeft) {
623 DEFINE_WAIT(wait);
624
625 while (write_sq.count >= write_sq.max_active) {
626 prepare_to_wait(&write_sq.action_queue, &wait, TASK_INTERRUPTIBLE);
627 sq_play();
628 if (write_sq.non_blocking) {
629 finish_wait(&write_sq.action_queue, &wait);
630 return uWritten > 0 ? uWritten : -EAGAIN;
631 }
632 if (write_sq.count < write_sq.max_active)
633 break;
634
635 schedule_timeout(HZ);
636 if (signal_pending(current)) {
637 finish_wait(&write_sq.action_queue, &wait);
638 return uWritten > 0 ? uWritten : -EINTR;
639 }
640 }
641
642 finish_wait(&write_sq.action_queue, &wait);
643
644
645
646
647
648
649
650
651 dest = write_sq.buffers[(write_sq.rear+1) % write_sq.max_count];
652 bUsed = 0;
653 bLeft = write_sq.block_size;
654 uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
655 dest, &bUsed, bLeft);
656 if (uUsed <= 0)
657 break;
658 src += uUsed;
659 uWritten += uUsed;
660 uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ;
661 if (bUsed) {
662 write_sq.rear = (write_sq.rear+1) % write_sq.max_count;
663 write_sq.rear_size = bUsed;
664 write_sq.count++;
665 }
666 }
667
668 sq_play();
669
670 return uUsed < 0? uUsed: uWritten;
671}
672
673static __poll_t sq_poll(struct file *file, struct poll_table_struct *wait)
674{
675 __poll_t mask = 0;
676 int retVal;
677
678 if (write_sq.locked == 0) {
679 if ((retVal = sq_setup(&write_sq)) < 0)
680 return retVal;
681 return 0;
682 }
683 if (file->f_mode & FMODE_WRITE )
684 poll_wait(file, &write_sq.action_queue, wait);
685 if (file->f_mode & FMODE_WRITE)
686 if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0)
687 mask |= EPOLLOUT | EPOLLWRNORM;
688 return mask;
689
690}
691
692static inline void sq_init_waitqueue(struct sound_queue *sq)
693{
694 init_waitqueue_head(&sq->action_queue);
695 init_waitqueue_head(&sq->open_queue);
696 init_waitqueue_head(&sq->sync_queue);
697 sq->busy = 0;
698}
699
700#if 0
701static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
702 fmode_t mode)
703{
704 if (file->f_mode & mode) {
705 sq->busy = 0;
706 WAKE_UP(sq->open_queue);
707 }
708}
709#endif
710
711static int sq_open2(struct sound_queue *sq, struct file *file, fmode_t mode,
712 int numbufs, int bufsize)
713{
714 int rc = 0;
715
716 if (file->f_mode & mode) {
717 if (sq->busy) {
718#if 0
719 rc = -EBUSY;
720 if (file->f_flags & O_NONBLOCK)
721 return rc;
722 rc = -EINTR;
723 if (wait_event_interruptible(sq->open_queue, !sq->busy))
724 return rc;
725 rc = 0;
726#else
727
728
729
730 return -EBUSY ;
731#endif
732 }
733 sq->busy = 1;
734
735
736
737
738
739
740 if (( rc = sq_allocate_buffers(sq, numbufs, bufsize))) {
741#if 0
742 sq_wake_up(sq, file, mode);
743#else
744 sq->busy = 0 ;
745#endif
746 return rc;
747 }
748
749 sq->non_blocking = file->f_flags & O_NONBLOCK;
750 }
751 return rc;
752}
753
754#define write_sq_init_waitqueue() sq_init_waitqueue(&write_sq)
755#if 0
756#define write_sq_wake_up(file) sq_wake_up(&write_sq, file, FMODE_WRITE)
757#endif
758#define write_sq_release_buffers() sq_release_buffers(&write_sq)
759#define write_sq_open(file) \
760 sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize )
761
762static int sq_open(struct inode *inode, struct file *file)
763{
764 int rc;
765
766 mutex_lock(&dmasound_core_mutex);
767 if (!try_module_get(dmasound.mach.owner)) {
768 mutex_unlock(&dmasound_core_mutex);
769 return -ENODEV;
770 }
771
772 rc = write_sq_open(file);
773 if (rc)
774 goto out;
775 if (file->f_mode & FMODE_READ) {
776
777 rc = -ENXIO ;
778 goto out;
779 }
780
781 if (dmasound.mach.sq_open)
782 dmasound.mach.sq_open(file->f_mode);
783
784
785
786
787
788 dmasound.minDev = iminor(inode) & 0x0f;
789
790
791
792
793
794
795 if (shared_resource_owner == 0) {
796
797
798 dmasound.soft = dmasound.mach.default_soft ;
799 dmasound.dsp = dmasound.mach.default_soft ;
800 dmasound.hard = dmasound.mach.default_hard ;
801 }
802
803#ifndef DMASOUND_STRICT_OSS_COMPLIANCE
804
805
806
807 if (dmasound.minDev == SND_DEV_AUDIO) {
808 sound_set_speed(8000);
809 sound_set_stereo(0);
810 sound_set_format(AFMT_MU_LAW);
811 }
812#endif
813 mutex_unlock(&dmasound_core_mutex);
814 return 0;
815 out:
816 module_put(dmasound.mach.owner);
817 mutex_unlock(&dmasound_core_mutex);
818 return rc;
819}
820
821static void sq_reset_output(void)
822{
823 sound_silence();
824 write_sq.active = 0;
825 write_sq.count = 0;
826 write_sq.rear_size = 0;
827
828 write_sq.front = 0 ;
829 write_sq.rear = -1 ;
830
831
832 write_sq.locked = 0 ;
833 write_sq.user_frags = 0 ;
834 write_sq.user_frag_size = 0 ;
835}
836
837static void sq_reset(void)
838{
839 sq_reset_output() ;
840
841
842
843
844
845 shared_resources_initialised = 0 ;
846}
847
848static int sq_fsync(void)
849{
850 int rc = 0;
851 int timeout = 5;
852
853 write_sq.syncing |= 1;
854 sq_play();
855
856 while (write_sq.active) {
857 wait_event_interruptible_timeout(write_sq.sync_queue,
858 !write_sq.active, HZ);
859 if (signal_pending(current)) {
860
861
862
863 sq_reset_output();
864 rc = -EINTR;
865 break;
866 }
867 if (!--timeout) {
868 printk(KERN_WARNING "dmasound: Timeout draining output\n");
869 sq_reset_output();
870 rc = -EIO;
871 break;
872 }
873 }
874
875
876 write_sq.syncing = 0 ;
877 return rc;
878}
879
880static int sq_release(struct inode *inode, struct file *file)
881{
882 int rc = 0;
883
884 mutex_lock(&dmasound_core_mutex);
885
886 if (file->f_mode & FMODE_WRITE) {
887 if (write_sq.busy)
888 rc = sq_fsync();
889
890 sq_reset_output() ;
891 write_sq_release_buffers();
892 write_sq.busy = 0;
893 }
894
895 if (file->f_mode & shared_resource_owner) {
896 shared_resource_owner = 0 ;
897 shared_resources_initialised = 0 ;
898 dmasound.hard = dmasound.mach.default_hard ;
899 }
900
901 module_put(dmasound.mach.owner);
902
903#if 0
904
905
906
907
908
909
910
911 read_sq_wake_up(file);
912 write_sq_wake_up(file);
913#endif
914
915 mutex_unlock(&dmasound_core_mutex);
916
917 return rc;
918}
919
920
921
922
923
924
925
926
927static int shared_resources_are_mine(fmode_t md)
928{
929 if (shared_resource_owner)
930 return (shared_resource_owner & md) != 0;
931 else {
932 shared_resource_owner = md ;
933 return 1 ;
934 }
935}
936
937
938
939
940static int queues_are_quiescent(void)
941{
942 if (write_sq.locked)
943 return 0 ;
944 return 1 ;
945}
946
947
948
949
950
951
952
953
954
955
956
957static int set_queue_frags(struct sound_queue *sq, int bufs, int size)
958{
959 if (sq->locked) {
960#ifdef DEBUG_DMASOUND
961printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;
962#endif
963 return -EINVAL ;
964 }
965
966 if ((size < MIN_FRAG_SIZE) || (size > MAX_FRAG_SIZE))
967 return -EINVAL ;
968 size = (1<<size) ;
969 if (size > sq->bufSize)
970 return -EINVAL ;
971
972 if (bufs <= 0)
973 return -EINVAL ;
974 if (bufs > sq->numBufs)
975 bufs = sq->numBufs ;
976
977
978
979
980
981
982 sq->user_frags =
983 sq->max_active = bufs ;
984 sq->user_frag_size = size ;
985
986 return 0 ;
987}
988
989static int sq_ioctl(struct file *file, u_int cmd, u_long arg)
990{
991 int val, result;
992 u_long fmt;
993 int data;
994 int size, nbufs;
995 audio_buf_info info;
996
997 switch (cmd) {
998 case SNDCTL_DSP_RESET:
999 sq_reset();
1000 return 0;
1001 break ;
1002 case SNDCTL_DSP_GETFMTS:
1003 fmt = dmasound.mach.hardware_afmts ;
1004 return IOCTL_OUT(arg, fmt);
1005 break ;
1006 case SNDCTL_DSP_GETBLKSIZE:
1007
1008
1009
1010
1011
1012
1013
1014
1015 size = 0 ;
1016 if (file->f_mode & FMODE_WRITE) {
1017 if ( !write_sq.locked )
1018 sq_setup(&write_sq) ;
1019 size = write_sq.user_frag_size ;
1020 }
1021 return IOCTL_OUT(arg, size);
1022 break ;
1023 case SNDCTL_DSP_POST:
1024
1025
1026
1027
1028
1029 write_sq.syncing |= 0x2 ;
1030 sq_play() ;
1031 return 0 ;
1032 case SNDCTL_DSP_SYNC:
1033
1034
1035
1036
1037 result = 0 ;
1038 if (file->f_mode & FMODE_WRITE) {
1039 result = sq_fsync();
1040 sq_reset_output() ;
1041 }
1042
1043 if (file->f_mode & shared_resource_owner)
1044 shared_resources_initialised = 0 ;
1045 return result ;
1046 break ;
1047 case SOUND_PCM_READ_RATE:
1048 return IOCTL_OUT(arg, dmasound.soft.speed);
1049 case SNDCTL_DSP_SPEED:
1050
1051
1052
1053
1054
1055
1056 if (shared_resources_are_mine(file->f_mode)) {
1057 IOCTL_IN(arg, data);
1058 data = sound_set_speed(data) ;
1059 shared_resources_initialised = 0 ;
1060 return IOCTL_OUT(arg, data);
1061 } else
1062 return -EINVAL ;
1063 break ;
1064
1065
1066
1067
1068
1069 case SNDCTL_DSP_STEREO:
1070 if (shared_resources_are_mine(file->f_mode) &&
1071 queues_are_quiescent()) {
1072 IOCTL_IN(arg, data);
1073 shared_resources_initialised = 0 ;
1074 return IOCTL_OUT(arg, sound_set_stereo(data));
1075 } else
1076 return -EINVAL ;
1077 break ;
1078 case SOUND_PCM_WRITE_CHANNELS:
1079 if (shared_resources_are_mine(file->f_mode) &&
1080 queues_are_quiescent()) {
1081 IOCTL_IN(arg, data);
1082
1083 shared_resources_initialised = 0 ;
1084 return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
1085 } else
1086 return -EINVAL ;
1087 break ;
1088 case SNDCTL_DSP_SETFMT:
1089 if (shared_resources_are_mine(file->f_mode) &&
1090 queues_are_quiescent()) {
1091 int format;
1092 IOCTL_IN(arg, data);
1093 shared_resources_initialised = 0 ;
1094 format = sound_set_format(data);
1095 result = IOCTL_OUT(arg, format);
1096 if (result < 0)
1097 return result;
1098 if (format != data && data != AFMT_QUERY)
1099 return -EINVAL;
1100 return 0;
1101 } else
1102 return -EINVAL ;
1103 case SNDCTL_DSP_SUBDIVIDE:
1104 return -EINVAL ;
1105 case SNDCTL_DSP_SETFRAGMENT:
1106
1107
1108
1109
1110
1111
1112 IOCTL_IN(arg, data);
1113 result = 0 ;
1114 nbufs = (data >> 16) & 0x7fff ;
1115 size = data & 0xffff;
1116 if (file->f_mode & FMODE_WRITE) {
1117 result = set_queue_frags(&write_sq, nbufs, size) ;
1118 if (result)
1119 return result ;
1120 }
1121
1122
1123
1124 return IOCTL_OUT(arg, data);
1125 break ;
1126 case SNDCTL_DSP_GETOSPACE:
1127
1128
1129 if (file->f_mode & FMODE_WRITE) {
1130 if ( !write_sq.locked )
1131 sq_setup(&write_sq) ;
1132 info.fragments = write_sq.max_active - write_sq.count;
1133 info.fragstotal = write_sq.max_active;
1134 info.fragsize = write_sq.user_frag_size;
1135 info.bytes = info.fragments * info.fragsize;
1136 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1137 return -EFAULT;
1138 return 0;
1139 } else
1140 return -EINVAL ;
1141 break ;
1142 case SNDCTL_DSP_GETCAPS:
1143 val = dmasound.mach.capabilities & 0xffffff00;
1144 return IOCTL_OUT(arg,val);
1145
1146 default:
1147 return mixer_ioctl(file, cmd, arg);
1148 }
1149 return -EINVAL;
1150}
1151
1152static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
1153{
1154 int ret;
1155
1156 mutex_lock(&dmasound_core_mutex);
1157 ret = sq_ioctl(file, cmd, arg);
1158 mutex_unlock(&dmasound_core_mutex);
1159
1160 return ret;
1161}
1162
1163static const struct file_operations sq_fops =
1164{
1165 .owner = THIS_MODULE,
1166 .llseek = no_llseek,
1167 .write = sq_write,
1168 .poll = sq_poll,
1169 .unlocked_ioctl = sq_unlocked_ioctl,
1170 .open = sq_open,
1171 .release = sq_release,
1172};
1173
1174static int sq_init(void)
1175{
1176 const struct file_operations *fops = &sq_fops;
1177#ifndef MODULE
1178 int sq_unit;
1179#endif
1180
1181 sq_unit = register_sound_dsp(fops, -1);
1182 if (sq_unit < 0) {
1183 printk(KERN_ERR "dmasound_core: couldn't register fops\n") ;
1184 return sq_unit ;
1185 }
1186
1187 write_sq_init_waitqueue();
1188
1189
1190
1191
1192
1193
1194 if (shared_resource_owner == 0) {
1195 dmasound.soft = dmasound.mach.default_soft ;
1196 dmasound.hard = dmasound.mach.default_hard ;
1197 dmasound.dsp = dmasound.mach.default_soft ;
1198 shared_resources_initialised = 0 ;
1199 }
1200 return 0 ;
1201}
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213#define STAT_BUFF_LEN 768
1214
1215
1216
1217
1218
1219
1220#define LOW_LEVEL_STAT_ALLOC 162
1221
1222static struct {
1223 int busy;
1224 char buf[STAT_BUFF_LEN];
1225 int len, ptr;
1226} state;
1227
1228
1229
1230static char *get_afmt_string(int afmt)
1231{
1232 switch(afmt) {
1233 case AFMT_MU_LAW:
1234 return "mu-law";
1235 break;
1236 case AFMT_A_LAW:
1237 return "A-law";
1238 break;
1239 case AFMT_U8:
1240 return "unsigned 8 bit";
1241 break;
1242 case AFMT_S8:
1243 return "signed 8 bit";
1244 break;
1245 case AFMT_S16_BE:
1246 return "signed 16 bit BE";
1247 break;
1248 case AFMT_U16_BE:
1249 return "unsigned 16 bit BE";
1250 break;
1251 case AFMT_S16_LE:
1252 return "signed 16 bit LE";
1253 break;
1254 case AFMT_U16_LE:
1255 return "unsigned 16 bit LE";
1256 break;
1257 case 0:
1258 return "format not set" ;
1259 break ;
1260 default:
1261 break ;
1262 }
1263 return "ERROR: Unsupported AFMT_XXXX code" ;
1264}
1265
1266static int state_open(struct inode *inode, struct file *file)
1267{
1268 char *buffer = state.buf;
1269 int len = 0;
1270 int ret;
1271
1272 mutex_lock(&dmasound_core_mutex);
1273 ret = -EBUSY;
1274 if (state.busy)
1275 goto out;
1276
1277 ret = -ENODEV;
1278 if (!try_module_get(dmasound.mach.owner))
1279 goto out;
1280
1281 state.ptr = 0;
1282 state.busy = 1;
1283
1284 len += sprintf(buffer+len, "%sDMA sound driver rev %03d :\n",
1285 dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) +
1286 ((dmasound.mach.version>>8) & 0x0f));
1287 len += sprintf(buffer+len,
1288 "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n",
1289 DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2,
1290 (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
1291
1292
1293
1294
1295
1296 if (dmasound.mach.state_info)
1297 len += dmasound.mach.state_info(buffer+len,
1298 (size_t) LOW_LEVEL_STAT_ALLOC) ;
1299
1300
1301
1302
1303
1304
1305
1306
1307 len += sprintf(buffer+len,"\t\t === Formats & settings ===\n") ;
1308 len += sprintf(buffer+len,"Parameter %20s%20s\n","soft","hard") ;
1309 len += sprintf(buffer+len,"Format :%20s%20s\n",
1310 get_afmt_string(dmasound.soft.format),
1311 get_afmt_string(dmasound.hard.format));
1312
1313 len += sprintf(buffer+len,"Samp Rate:%14d s/sec%14d s/sec\n",
1314 dmasound.soft.speed, dmasound.hard.speed);
1315
1316 len += sprintf(buffer+len,"Channels :%20s%20s\n",
1317 dmasound.soft.stereo ? "stereo" : "mono",
1318 dmasound.hard.stereo ? "stereo" : "mono" );
1319
1320
1321
1322 len += sprintf(buffer+len,"\t\t === Sound Queue status ===\n");
1323 len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ;
1324 len += sprintf(buffer+len,"%9s:%8d%6d\n",
1325 "write", write_sq.numBufs, write_sq.bufSize) ;
1326 len += sprintf(buffer+len,
1327 "Current : MaxFrg FragSiz MaxAct Frnt Rear "
1328 "Cnt RrSize A B S L xruns\n") ;
1329 len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n",
1330 "write", write_sq.max_count, write_sq.block_size,
1331 write_sq.max_active, write_sq.front, write_sq.rear,
1332 write_sq.count, write_sq.rear_size, write_sq.active,
1333 write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ;
1334#ifdef DEBUG_DMASOUND
1335printk("dmasound: stat buffer used %d bytes\n", len) ;
1336#endif
1337
1338 if (len >= STAT_BUFF_LEN)
1339 printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
1340
1341 state.len = len;
1342 ret = 0;
1343out:
1344 mutex_unlock(&dmasound_core_mutex);
1345 return ret;
1346}
1347
1348static int state_release(struct inode *inode, struct file *file)
1349{
1350 mutex_lock(&dmasound_core_mutex);
1351 state.busy = 0;
1352 module_put(dmasound.mach.owner);
1353 mutex_unlock(&dmasound_core_mutex);
1354 return 0;
1355}
1356
1357static ssize_t state_read(struct file *file, char __user *buf, size_t count,
1358 loff_t *ppos)
1359{
1360 int n = state.len - state.ptr;
1361 if (n > count)
1362 n = count;
1363 if (n <= 0)
1364 return 0;
1365 if (copy_to_user(buf, &state.buf[state.ptr], n))
1366 return -EFAULT;
1367 state.ptr += n;
1368 return n;
1369}
1370
1371static const struct file_operations state_fops = {
1372 .owner = THIS_MODULE,
1373 .llseek = no_llseek,
1374 .read = state_read,
1375 .open = state_open,
1376 .release = state_release,
1377};
1378
1379static int state_init(void)
1380{
1381#ifndef MODULE
1382 int state_unit;
1383#endif
1384 state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
1385 if (state_unit < 0)
1386 return state_unit ;
1387 state.busy = 0;
1388 return 0 ;
1389}
1390
1391
1392
1393
1394
1395
1396
1397
1398int dmasound_init(void)
1399{
1400 int res ;
1401#ifdef MODULE
1402 if (irq_installed)
1403 return -EBUSY;
1404#endif
1405
1406
1407
1408
1409 if ((res = sq_init()) < 0)
1410 return res ;
1411
1412
1413 if ((res = state_init()) < 0)
1414 return res ;
1415
1416
1417 mixer_init();
1418
1419 if (!dmasound.mach.irqinit()) {
1420 printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
1421 return -ENODEV;
1422 }
1423#ifdef MODULE
1424 irq_installed = 1;
1425#endif
1426
1427 printk(KERN_INFO "%s DMA sound driver rev %03d installed\n",
1428 dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) +
1429 ((dmasound.mach.version>>8) & 0x0f));
1430 printk(KERN_INFO
1431 "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n",
1432 DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2,
1433 (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
1434 printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n",
1435 numWriteBufs, writeBufSize) ;
1436 return 0;
1437}
1438
1439#ifdef MODULE
1440
1441void dmasound_deinit(void)
1442{
1443 if (irq_installed) {
1444 sound_silence();
1445 dmasound.mach.irqcleanup();
1446 irq_installed = 0;
1447 }
1448
1449 write_sq_release_buffers();
1450
1451 if (mixer_unit >= 0)
1452 unregister_sound_mixer(mixer_unit);
1453 if (state_unit >= 0)
1454 unregister_sound_special(state_unit);
1455 if (sq_unit >= 0)
1456 unregister_sound_dsp(sq_unit);
1457}
1458
1459#else
1460
1461static int dmasound_setup(char *str)
1462{
1463 int ints[6], size;
1464
1465 str = get_options(str, ARRAY_SIZE(ints), ints);
1466
1467
1468
1469
1470
1471
1472
1473 switch (ints[0]) {
1474 case 3:
1475 if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
1476 printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
1477 else
1478 catchRadius = ints[3];
1479
1480 case 2:
1481 if (ints[1] < MIN_BUFFERS)
1482 printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs);
1483 else
1484 numWriteBufs = ints[1];
1485
1486 case 1:
1487 if ((size = ints[2]) < 256)
1488 size <<= 10 ;
1489 if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
1490 printk("dmasound_setup: invalid write buffer size, using default = %d\n", writeBufSize);
1491 else
1492 writeBufSize = size;
1493 case 0:
1494 break;
1495 default:
1496 printk("dmasound_setup: invalid number of arguments\n");
1497 return 0;
1498 }
1499 return 1;
1500}
1501
1502__setup("dmasound=", dmasound_setup);
1503
1504#endif
1505
1506
1507
1508
1509
1510#ifdef HAS_8BIT_TABLES
1511
1512
1513char dmasound_ulaw2dma8[] = {
1514 -126, -122, -118, -114, -110, -106, -102, -98,
1515 -94, -90, -86, -82, -78, -74, -70, -66,
1516 -63, -61, -59, -57, -55, -53, -51, -49,
1517 -47, -45, -43, -41, -39, -37, -35, -33,
1518 -31, -30, -29, -28, -27, -26, -25, -24,
1519 -23, -22, -21, -20, -19, -18, -17, -16,
1520 -16, -15, -15, -14, -14, -13, -13, -12,
1521 -12, -11, -11, -10, -10, -9, -9, -8,
1522 -8, -8, -7, -7, -7, -7, -6, -6,
1523 -6, -6, -5, -5, -5, -5, -4, -4,
1524 -4, -4, -4, -4, -3, -3, -3, -3,
1525 -3, -3, -3, -3, -2, -2, -2, -2,
1526 -2, -2, -2, -2, -2, -2, -2, -2,
1527 -1, -1, -1, -1, -1, -1, -1, -1,
1528 -1, -1, -1, -1, -1, -1, -1, -1,
1529 -1, -1, -1, -1, -1, -1, -1, 0,
1530 125, 121, 117, 113, 109, 105, 101, 97,
1531 93, 89, 85, 81, 77, 73, 69, 65,
1532 62, 60, 58, 56, 54, 52, 50, 48,
1533 46, 44, 42, 40, 38, 36, 34, 32,
1534 30, 29, 28, 27, 26, 25, 24, 23,
1535 22, 21, 20, 19, 18, 17, 16, 15,
1536 15, 14, 14, 13, 13, 12, 12, 11,
1537 11, 10, 10, 9, 9, 8, 8, 7,
1538 7, 7, 6, 6, 6, 6, 5, 5,
1539 5, 5, 4, 4, 4, 4, 3, 3,
1540 3, 3, 3, 3, 2, 2, 2, 2,
1541 2, 2, 2, 2, 1, 1, 1, 1,
1542 1, 1, 1, 1, 1, 1, 1, 1,
1543 0, 0, 0, 0, 0, 0, 0, 0,
1544 0, 0, 0, 0, 0, 0, 0, 0,
1545 0, 0, 0, 0, 0, 0, 0, 0
1546};
1547
1548
1549
1550char dmasound_alaw2dma8[] = {
1551 -22, -21, -24, -23, -18, -17, -20, -19,
1552 -30, -29, -32, -31, -26, -25, -28, -27,
1553 -11, -11, -12, -12, -9, -9, -10, -10,
1554 -15, -15, -16, -16, -13, -13, -14, -14,
1555 -86, -82, -94, -90, -70, -66, -78, -74,
1556 -118, -114, -126, -122, -102, -98, -110, -106,
1557 -43, -41, -47, -45, -35, -33, -39, -37,
1558 -59, -57, -63, -61, -51, -49, -55, -53,
1559 -2, -2, -2, -2, -2, -2, -2, -2,
1560 -2, -2, -2, -2, -2, -2, -2, -2,
1561 -1, -1, -1, -1, -1, -1, -1, -1,
1562 -1, -1, -1, -1, -1, -1, -1, -1,
1563 -6, -6, -6, -6, -5, -5, -5, -5,
1564 -8, -8, -8, -8, -7, -7, -7, -7,
1565 -3, -3, -3, -3, -3, -3, -3, -3,
1566 -4, -4, -4, -4, -4, -4, -4, -4,
1567 21, 20, 23, 22, 17, 16, 19, 18,
1568 29, 28, 31, 30, 25, 24, 27, 26,
1569 10, 10, 11, 11, 8, 8, 9, 9,
1570 14, 14, 15, 15, 12, 12, 13, 13,
1571 86, 82, 94, 90, 70, 66, 78, 74,
1572 118, 114, 126, 122, 102, 98, 110, 106,
1573 43, 41, 47, 45, 35, 33, 39, 37,
1574 59, 57, 63, 61, 51, 49, 55, 53,
1575 1, 1, 1, 1, 1, 1, 1, 1,
1576 1, 1, 1, 1, 1, 1, 1, 1,
1577 0, 0, 0, 0, 0, 0, 0, 0,
1578 0, 0, 0, 0, 0, 0, 0, 0,
1579 5, 5, 5, 5, 4, 4, 4, 4,
1580 7, 7, 7, 7, 6, 6, 6, 6,
1581 2, 2, 2, 2, 2, 2, 2, 2,
1582 3, 3, 3, 3, 3, 3, 3, 3
1583};
1584#endif
1585
1586
1587
1588
1589
1590EXPORT_SYMBOL(dmasound);
1591EXPORT_SYMBOL(dmasound_init);
1592#ifdef MODULE
1593EXPORT_SYMBOL(dmasound_deinit);
1594#endif
1595EXPORT_SYMBOL(dmasound_write_sq);
1596EXPORT_SYMBOL(dmasound_catchRadius);
1597#ifdef HAS_8BIT_TABLES
1598EXPORT_SYMBOL(dmasound_ulaw2dma8);
1599EXPORT_SYMBOL(dmasound_alaw2dma8);
1600#endif
1601