0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178 #include <linux/module.h>
0179 #include <linux/slab.h>
0180 #include <linux/sound.h>
0181 #include <linux/init.h>
0182 #include <linux/soundcard.h>
0183 #include <linux/poll.h>
0184 #include <linux/mutex.h>
0185 #include <linux/sched/signal.h>
0186
0187 #include <linux/uaccess.h>
0188
0189 #include "dmasound.h"
0190
0191 #define DMASOUND_CORE_REVISION 1
0192 #define DMASOUND_CORE_EDITION 6
0193
0194
0195
0196
0197
0198 static DEFINE_MUTEX(dmasound_core_mutex);
0199 int dmasound_catchRadius = 0;
0200 module_param(dmasound_catchRadius, int, 0);
0201
0202 static unsigned int numWriteBufs = DEFAULT_N_BUFFERS;
0203 module_param(numWriteBufs, int, 0);
0204 static unsigned int writeBufSize = DEFAULT_BUFF_SIZE ;
0205 module_param(writeBufSize, int, 0);
0206
0207 MODULE_LICENSE("GPL");
0208
0209 static int sq_unit = -1;
0210 static int mixer_unit = -1;
0211 static int state_unit = -1;
0212 static int irq_installed;
0213
0214
0215 static fmode_t shared_resource_owner;
0216 static int shared_resources_initialised;
0217
0218
0219
0220
0221
0222 struct sound_settings dmasound = {
0223 .lock = __SPIN_LOCK_UNLOCKED(dmasound.lock)
0224 };
0225
0226 static inline void sound_silence(void)
0227 {
0228 dmasound.mach.silence();
0229 }
0230
0231 static inline int sound_set_format(int format)
0232 {
0233 return dmasound.mach.setFormat(format);
0234 }
0235
0236
0237 static int sound_set_speed(int speed)
0238 {
0239 if (speed < 0)
0240 return dmasound.soft.speed;
0241
0242
0243
0244
0245
0246
0247 if (dmasound.mach.max_dsp_speed &&
0248 (speed > dmasound.mach.max_dsp_speed))
0249 speed = dmasound.mach.max_dsp_speed ;
0250
0251 dmasound.soft.speed = speed;
0252
0253 if (dmasound.minDev == SND_DEV_DSP)
0254 dmasound.dsp.speed = dmasound.soft.speed;
0255
0256 return dmasound.soft.speed;
0257 }
0258
0259 static int sound_set_stereo(int stereo)
0260 {
0261 if (stereo < 0)
0262 return dmasound.soft.stereo;
0263
0264 stereo = !!stereo;
0265
0266 dmasound.soft.stereo = stereo;
0267 if (dmasound.minDev == SND_DEV_DSP)
0268 dmasound.dsp.stereo = stereo;
0269
0270 return stereo;
0271 }
0272
0273 static ssize_t sound_copy_translate(TRANS *trans, const u_char __user *userPtr,
0274 size_t userCount, u_char frame[],
0275 ssize_t *frameUsed, ssize_t frameLeft)
0276 {
0277 ssize_t (*ct_func)(const u_char __user *, size_t, u_char *, ssize_t *, ssize_t);
0278
0279 switch (dmasound.soft.format) {
0280 case AFMT_MU_LAW:
0281 ct_func = trans->ct_ulaw;
0282 break;
0283 case AFMT_A_LAW:
0284 ct_func = trans->ct_alaw;
0285 break;
0286 case AFMT_S8:
0287 ct_func = trans->ct_s8;
0288 break;
0289 case AFMT_U8:
0290 ct_func = trans->ct_u8;
0291 break;
0292 case AFMT_S16_BE:
0293 ct_func = trans->ct_s16be;
0294 break;
0295 case AFMT_U16_BE:
0296 ct_func = trans->ct_u16be;
0297 break;
0298 case AFMT_S16_LE:
0299 ct_func = trans->ct_s16le;
0300 break;
0301 case AFMT_U16_LE:
0302 ct_func = trans->ct_u16le;
0303 break;
0304 default:
0305 return 0;
0306 }
0307
0308
0309
0310 if (ct_func)
0311 return ct_func(userPtr, userCount, frame, frameUsed, frameLeft);
0312 return 0;
0313 }
0314
0315
0316
0317
0318
0319 static struct {
0320 int busy;
0321 int modify_counter;
0322 } mixer;
0323
0324 static int mixer_open(struct inode *inode, struct file *file)
0325 {
0326 mutex_lock(&dmasound_core_mutex);
0327 if (!try_module_get(dmasound.mach.owner)) {
0328 mutex_unlock(&dmasound_core_mutex);
0329 return -ENODEV;
0330 }
0331 mixer.busy = 1;
0332 mutex_unlock(&dmasound_core_mutex);
0333 return 0;
0334 }
0335
0336 static int mixer_release(struct inode *inode, struct file *file)
0337 {
0338 mutex_lock(&dmasound_core_mutex);
0339 mixer.busy = 0;
0340 module_put(dmasound.mach.owner);
0341 mutex_unlock(&dmasound_core_mutex);
0342 return 0;
0343 }
0344
0345 static int mixer_ioctl(struct file *file, u_int cmd, u_long arg)
0346 {
0347 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
0348 mixer.modify_counter++;
0349 switch (cmd) {
0350 case OSS_GETVERSION:
0351 return IOCTL_OUT(arg, SOUND_VERSION);
0352 case SOUND_MIXER_INFO:
0353 {
0354 mixer_info info;
0355 memset(&info, 0, sizeof(info));
0356 strscpy(info.id, dmasound.mach.name2, sizeof(info.id));
0357 strscpy(info.name, dmasound.mach.name2, sizeof(info.name));
0358 info.modify_counter = mixer.modify_counter;
0359 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
0360 return -EFAULT;
0361 return 0;
0362 }
0363 }
0364 if (dmasound.mach.mixer_ioctl)
0365 return dmasound.mach.mixer_ioctl(cmd, arg);
0366 return -EINVAL;
0367 }
0368
0369 static long mixer_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
0370 {
0371 int ret;
0372
0373 mutex_lock(&dmasound_core_mutex);
0374 ret = mixer_ioctl(file, cmd, arg);
0375 mutex_unlock(&dmasound_core_mutex);
0376
0377 return ret;
0378 }
0379
0380 static const struct file_operations mixer_fops =
0381 {
0382 .owner = THIS_MODULE,
0383 .llseek = no_llseek,
0384 .unlocked_ioctl = mixer_unlocked_ioctl,
0385 .compat_ioctl = compat_ptr_ioctl,
0386 .open = mixer_open,
0387 .release = mixer_release,
0388 };
0389
0390 static void mixer_init(void)
0391 {
0392 mixer_unit = register_sound_mixer(&mixer_fops, -1);
0393 if (mixer_unit < 0)
0394 return;
0395
0396 mixer.busy = 0;
0397 dmasound.treble = 0;
0398 dmasound.bass = 0;
0399 if (dmasound.mach.mixer_init)
0400 dmasound.mach.mixer_init();
0401 }
0402
0403
0404
0405
0406
0407
0408 struct sound_queue dmasound_write_sq;
0409 static void sq_reset_output(void) ;
0410
0411 static int sq_allocate_buffers(struct sound_queue *sq, int num, int size)
0412 {
0413 int i;
0414
0415 if (sq->buffers)
0416 return 0;
0417 sq->numBufs = num;
0418 sq->bufSize = size;
0419 sq->buffers = kmalloc_array (num, sizeof(char *), GFP_KERNEL);
0420 if (!sq->buffers)
0421 return -ENOMEM;
0422 for (i = 0; i < num; i++) {
0423 sq->buffers[i] = dmasound.mach.dma_alloc(size, GFP_KERNEL);
0424 if (!sq->buffers[i]) {
0425 while (i--)
0426 dmasound.mach.dma_free(sq->buffers[i], size);
0427 kfree(sq->buffers);
0428 sq->buffers = NULL;
0429 return -ENOMEM;
0430 }
0431 }
0432 return 0;
0433 }
0434
0435 static void sq_release_buffers(struct sound_queue *sq)
0436 {
0437 int i;
0438
0439 if (sq->buffers) {
0440 for (i = 0; i < sq->numBufs; i++)
0441 dmasound.mach.dma_free(sq->buffers[i], sq->bufSize);
0442 kfree(sq->buffers);
0443 sq->buffers = NULL;
0444 }
0445 }
0446
0447
0448 static int sq_setup(struct sound_queue *sq)
0449 {
0450 int (*setup_func)(void) = NULL;
0451 int hard_frame ;
0452
0453 if (sq->locked) {
0454 #ifdef DEBUG_DMASOUND
0455 printk("dmasound_core: tried to sq_setup a locked queue\n") ;
0456 #endif
0457 return -EINVAL ;
0458 }
0459 sq->locked = 1 ;
0460
0461
0462
0463
0464
0465 dmasound.mach.init();
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479 if (sq->user_frags <= 0) {
0480 sq->max_count = sq->numBufs ;
0481 sq->max_active = sq->numBufs ;
0482 sq->block_size = sq->bufSize;
0483
0484 sq->user_frags = sq->numBufs ;
0485 sq->user_frag_size = sq->bufSize ;
0486 sq->user_frag_size *=
0487 (dmasound.soft.size * (dmasound.soft.stereo+1) ) ;
0488 sq->user_frag_size /=
0489 (dmasound.hard.size * (dmasound.hard.stereo+1) ) ;
0490 } else {
0491
0492 sq->block_size = sq->user_frag_size ;
0493 sq->block_size *=
0494 (dmasound.hard.size * (dmasound.hard.stereo+1) ) ;
0495 sq->block_size /=
0496 (dmasound.soft.size * (dmasound.soft.stereo+1) ) ;
0497
0498 sq->block_size *= dmasound.hard.speed ;
0499 sq->block_size /= dmasound.soft.speed ;
0500
0501 hard_frame =
0502 (dmasound.hard.size * (dmasound.hard.stereo+1))/8 ;
0503 sq->block_size += (hard_frame - 1) ;
0504 sq->block_size &= ~(hard_frame - 1) ;
0505
0506 if ( sq->block_size <= 0 || sq->block_size > sq->bufSize) {
0507 #ifdef DEBUG_DMASOUND
0508 printk("dmasound_core: invalid frag size (user set %d)\n", sq->user_frag_size) ;
0509 #endif
0510 sq->block_size = sq->bufSize ;
0511 }
0512 if ( sq->user_frags <= sq->numBufs ) {
0513 sq->max_count = sq->user_frags ;
0514
0515 sq->max_active = (sq->max_active <= sq->max_count) ?
0516 sq->max_active : sq->max_count ;
0517 } else {
0518 #ifdef DEBUG_DMASOUND
0519 printk("dmasound_core: invalid frag count (user set %d)\n", sq->user_frags) ;
0520 #endif
0521 sq->max_count =
0522 sq->max_active = sq->numBufs ;
0523 }
0524 }
0525 sq->front = sq->count = sq->rear_size = 0;
0526 sq->syncing = 0;
0527 sq->active = 0;
0528
0529 if (sq == &write_sq) {
0530 sq->rear = -1;
0531 setup_func = dmasound.mach.write_sq_setup;
0532 }
0533 if (setup_func)
0534 return setup_func();
0535 return 0 ;
0536 }
0537
0538 static inline void sq_play(void)
0539 {
0540 dmasound.mach.play();
0541 }
0542
0543 static ssize_t sq_write(struct file *file, const char __user *src, size_t uLeft,
0544 loff_t *ppos)
0545 {
0546 ssize_t uWritten = 0;
0547 u_char *dest;
0548 ssize_t uUsed = 0, bUsed, bLeft;
0549 unsigned long flags ;
0550
0551
0552
0553
0554
0555 if (uLeft == 0)
0556 return 0;
0557
0558
0559
0560
0561
0562
0563 if (shared_resources_initialised == 0) {
0564 dmasound.mach.init() ;
0565 shared_resources_initialised = 1 ;
0566 }
0567
0568
0569
0570
0571
0572
0573
0574
0575 if (write_sq.locked == 0) {
0576 if ((uWritten = sq_setup(&write_sq)) < 0) return uWritten ;
0577 uWritten = 0 ;
0578 }
0579
0580
0581
0582
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593
0594
0595
0596
0597
0598
0599
0600 spin_lock_irqsave(&dmasound.lock, flags);
0601 write_sq.syncing &= ~2 ;
0602 spin_unlock_irqrestore(&dmasound.lock, flags);
0603
0604 if (write_sq.count > 0 &&
0605 (bLeft = write_sq.block_size-write_sq.rear_size) > 0) {
0606 dest = write_sq.buffers[write_sq.rear];
0607 bUsed = write_sq.rear_size;
0608 uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
0609 dest, &bUsed, bLeft);
0610 if (uUsed <= 0)
0611 return uUsed;
0612 src += uUsed;
0613 uWritten += uUsed;
0614 uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ;
0615 write_sq.rear_size = bUsed;
0616 }
0617
0618 while (uLeft) {
0619 DEFINE_WAIT(wait);
0620
0621 while (write_sq.count >= write_sq.max_active) {
0622 prepare_to_wait(&write_sq.action_queue, &wait, TASK_INTERRUPTIBLE);
0623 sq_play();
0624 if (write_sq.non_blocking) {
0625 finish_wait(&write_sq.action_queue, &wait);
0626 return uWritten > 0 ? uWritten : -EAGAIN;
0627 }
0628 if (write_sq.count < write_sq.max_active)
0629 break;
0630
0631 schedule_timeout(HZ);
0632 if (signal_pending(current)) {
0633 finish_wait(&write_sq.action_queue, &wait);
0634 return uWritten > 0 ? uWritten : -EINTR;
0635 }
0636 }
0637
0638 finish_wait(&write_sq.action_queue, &wait);
0639
0640
0641
0642
0643
0644
0645
0646
0647 dest = write_sq.buffers[(write_sq.rear+1) % write_sq.max_count];
0648 bUsed = 0;
0649 bLeft = write_sq.block_size;
0650 uUsed = sound_copy_translate(dmasound.trans_write, src, uLeft,
0651 dest, &bUsed, bLeft);
0652 if (uUsed <= 0)
0653 break;
0654 src += uUsed;
0655 uWritten += uUsed;
0656 uLeft = (uUsed <= uLeft) ? (uLeft - uUsed) : 0 ;
0657 if (bUsed) {
0658 write_sq.rear = (write_sq.rear+1) % write_sq.max_count;
0659 write_sq.rear_size = bUsed;
0660 write_sq.count++;
0661 }
0662 }
0663
0664 sq_play();
0665
0666 return uUsed < 0? uUsed: uWritten;
0667 }
0668
0669 static __poll_t sq_poll(struct file *file, struct poll_table_struct *wait)
0670 {
0671 __poll_t mask = 0;
0672 int retVal;
0673
0674 if (write_sq.locked == 0) {
0675 if ((retVal = sq_setup(&write_sq)) < 0)
0676 return retVal;
0677 return 0;
0678 }
0679 if (file->f_mode & FMODE_WRITE )
0680 poll_wait(file, &write_sq.action_queue, wait);
0681 if (file->f_mode & FMODE_WRITE)
0682 if (write_sq.count < write_sq.max_active || write_sq.block_size - write_sq.rear_size > 0)
0683 mask |= EPOLLOUT | EPOLLWRNORM;
0684 return mask;
0685
0686 }
0687
0688 static inline void sq_init_waitqueue(struct sound_queue *sq)
0689 {
0690 init_waitqueue_head(&sq->action_queue);
0691 init_waitqueue_head(&sq->open_queue);
0692 init_waitqueue_head(&sq->sync_queue);
0693 sq->busy = 0;
0694 }
0695
0696 #if 0
0697 static inline void sq_wake_up(struct sound_queue *sq, struct file *file,
0698 fmode_t mode)
0699 {
0700 if (file->f_mode & mode) {
0701 sq->busy = 0;
0702 WAKE_UP(sq->open_queue);
0703 }
0704 }
0705 #endif
0706
0707 static int sq_open2(struct sound_queue *sq, struct file *file, fmode_t mode,
0708 int numbufs, int bufsize)
0709 {
0710 int rc = 0;
0711
0712 if (file->f_mode & mode) {
0713 if (sq->busy) {
0714 #if 0
0715 rc = -EBUSY;
0716 if (file->f_flags & O_NONBLOCK)
0717 return rc;
0718 rc = -EINTR;
0719 if (wait_event_interruptible(sq->open_queue, !sq->busy))
0720 return rc;
0721 rc = 0;
0722 #else
0723
0724
0725
0726 return -EBUSY ;
0727 #endif
0728 }
0729 sq->busy = 1;
0730
0731
0732
0733
0734
0735
0736 if (( rc = sq_allocate_buffers(sq, numbufs, bufsize))) {
0737 #if 0
0738 sq_wake_up(sq, file, mode);
0739 #else
0740 sq->busy = 0 ;
0741 #endif
0742 return rc;
0743 }
0744
0745 sq->non_blocking = file->f_flags & O_NONBLOCK;
0746 }
0747 return rc;
0748 }
0749
0750 #define write_sq_init_waitqueue() sq_init_waitqueue(&write_sq)
0751 #if 0
0752 #define write_sq_wake_up(file) sq_wake_up(&write_sq, file, FMODE_WRITE)
0753 #endif
0754 #define write_sq_release_buffers() sq_release_buffers(&write_sq)
0755 #define write_sq_open(file) \
0756 sq_open2(&write_sq, file, FMODE_WRITE, numWriteBufs, writeBufSize )
0757
0758 static int sq_open(struct inode *inode, struct file *file)
0759 {
0760 int rc;
0761
0762 mutex_lock(&dmasound_core_mutex);
0763 if (!try_module_get(dmasound.mach.owner)) {
0764 mutex_unlock(&dmasound_core_mutex);
0765 return -ENODEV;
0766 }
0767
0768 rc = write_sq_open(file);
0769 if (rc)
0770 goto out;
0771 if (file->f_mode & FMODE_READ) {
0772
0773 rc = -ENXIO ;
0774 goto out;
0775 }
0776
0777 if (dmasound.mach.sq_open)
0778 dmasound.mach.sq_open(file->f_mode);
0779
0780
0781
0782
0783
0784 dmasound.minDev = iminor(inode) & 0x0f;
0785
0786
0787
0788
0789
0790
0791 if (shared_resource_owner == 0) {
0792
0793
0794 dmasound.soft = dmasound.mach.default_soft ;
0795 dmasound.dsp = dmasound.mach.default_soft ;
0796 dmasound.hard = dmasound.mach.default_hard ;
0797 }
0798
0799 #ifndef DMASOUND_STRICT_OSS_COMPLIANCE
0800
0801
0802
0803 if (dmasound.minDev == SND_DEV_AUDIO) {
0804 sound_set_speed(8000);
0805 sound_set_stereo(0);
0806 sound_set_format(AFMT_MU_LAW);
0807 }
0808 #endif
0809 mutex_unlock(&dmasound_core_mutex);
0810 return 0;
0811 out:
0812 module_put(dmasound.mach.owner);
0813 mutex_unlock(&dmasound_core_mutex);
0814 return rc;
0815 }
0816
0817 static void sq_reset_output(void)
0818 {
0819 sound_silence();
0820 write_sq.active = 0;
0821 write_sq.count = 0;
0822 write_sq.rear_size = 0;
0823
0824 write_sq.front = 0 ;
0825 write_sq.rear = -1 ;
0826
0827
0828 write_sq.locked = 0 ;
0829 write_sq.user_frags = 0 ;
0830 write_sq.user_frag_size = 0 ;
0831 }
0832
0833 static void sq_reset(void)
0834 {
0835 sq_reset_output() ;
0836
0837
0838
0839
0840
0841 shared_resources_initialised = 0 ;
0842 }
0843
0844 static int sq_fsync(void)
0845 {
0846 int rc = 0;
0847 int timeout = 5;
0848
0849 write_sq.syncing |= 1;
0850 sq_play();
0851
0852 while (write_sq.active) {
0853 wait_event_interruptible_timeout(write_sq.sync_queue,
0854 !write_sq.active, HZ);
0855 if (signal_pending(current)) {
0856
0857
0858
0859 sq_reset_output();
0860 rc = -EINTR;
0861 break;
0862 }
0863 if (!--timeout) {
0864 printk(KERN_WARNING "dmasound: Timeout draining output\n");
0865 sq_reset_output();
0866 rc = -EIO;
0867 break;
0868 }
0869 }
0870
0871
0872 write_sq.syncing = 0 ;
0873 return rc;
0874 }
0875
0876 static int sq_release(struct inode *inode, struct file *file)
0877 {
0878 int rc = 0;
0879
0880 mutex_lock(&dmasound_core_mutex);
0881
0882 if (file->f_mode & FMODE_WRITE) {
0883 if (write_sq.busy)
0884 rc = sq_fsync();
0885
0886 sq_reset_output() ;
0887 write_sq_release_buffers();
0888 write_sq.busy = 0;
0889 }
0890
0891 if (file->f_mode & shared_resource_owner) {
0892 shared_resource_owner = 0 ;
0893 shared_resources_initialised = 0 ;
0894 dmasound.hard = dmasound.mach.default_hard ;
0895 }
0896
0897 module_put(dmasound.mach.owner);
0898
0899 #if 0
0900
0901
0902
0903
0904
0905
0906
0907 read_sq_wake_up(file);
0908 write_sq_wake_up(file);
0909 #endif
0910
0911 mutex_unlock(&dmasound_core_mutex);
0912
0913 return rc;
0914 }
0915
0916
0917
0918
0919
0920
0921
0922
0923 static int shared_resources_are_mine(fmode_t md)
0924 {
0925 if (shared_resource_owner)
0926 return (shared_resource_owner & md) != 0;
0927 else {
0928 shared_resource_owner = md ;
0929 return 1 ;
0930 }
0931 }
0932
0933
0934
0935
0936 static int queues_are_quiescent(void)
0937 {
0938 if (write_sq.locked)
0939 return 0 ;
0940 return 1 ;
0941 }
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953 static int set_queue_frags(struct sound_queue *sq, int bufs, int size)
0954 {
0955 if (sq->locked) {
0956 #ifdef DEBUG_DMASOUND
0957 printk("dmasound_core: tried to set_queue_frags on a locked queue\n") ;
0958 #endif
0959 return -EINVAL ;
0960 }
0961
0962 if ((size < MIN_FRAG_SIZE) || (size > MAX_FRAG_SIZE))
0963 return -EINVAL ;
0964 size = (1<<size) ;
0965 if (size > sq->bufSize)
0966 return -EINVAL ;
0967
0968 if (bufs <= 0)
0969 return -EINVAL ;
0970 if (bufs > sq->numBufs)
0971 bufs = sq->numBufs ;
0972
0973
0974
0975
0976
0977
0978 sq->user_frags =
0979 sq->max_active = bufs ;
0980 sq->user_frag_size = size ;
0981
0982 return 0 ;
0983 }
0984
0985 static int sq_ioctl(struct file *file, u_int cmd, u_long arg)
0986 {
0987 int val, result;
0988 u_long fmt;
0989 int data;
0990 int size, nbufs;
0991 audio_buf_info info;
0992
0993 switch (cmd) {
0994 case SNDCTL_DSP_RESET:
0995 sq_reset();
0996 return 0;
0997 case SNDCTL_DSP_GETFMTS:
0998 fmt = dmasound.mach.hardware_afmts ;
0999 return IOCTL_OUT(arg, fmt);
1000 case SNDCTL_DSP_GETBLKSIZE:
1001
1002
1003
1004
1005
1006
1007
1008
1009 size = 0 ;
1010 if (file->f_mode & FMODE_WRITE) {
1011 if ( !write_sq.locked )
1012 sq_setup(&write_sq) ;
1013 size = write_sq.user_frag_size ;
1014 }
1015 return IOCTL_OUT(arg, size);
1016 case SNDCTL_DSP_POST:
1017
1018
1019
1020
1021
1022 write_sq.syncing |= 0x2 ;
1023 sq_play() ;
1024 return 0 ;
1025 case SNDCTL_DSP_SYNC:
1026
1027
1028
1029
1030 result = 0 ;
1031 if (file->f_mode & FMODE_WRITE) {
1032 result = sq_fsync();
1033 sq_reset_output() ;
1034 }
1035
1036 if (file->f_mode & shared_resource_owner)
1037 shared_resources_initialised = 0 ;
1038 return result ;
1039 case SOUND_PCM_READ_RATE:
1040 return IOCTL_OUT(arg, dmasound.soft.speed);
1041 case SNDCTL_DSP_SPEED:
1042
1043
1044
1045
1046
1047
1048 if (shared_resources_are_mine(file->f_mode)) {
1049 IOCTL_IN(arg, data);
1050 data = sound_set_speed(data) ;
1051 shared_resources_initialised = 0 ;
1052 return IOCTL_OUT(arg, data);
1053 } else
1054 return -EINVAL ;
1055 break ;
1056
1057
1058
1059
1060
1061 case SNDCTL_DSP_STEREO:
1062 if (shared_resources_are_mine(file->f_mode) &&
1063 queues_are_quiescent()) {
1064 IOCTL_IN(arg, data);
1065 shared_resources_initialised = 0 ;
1066 return IOCTL_OUT(arg, sound_set_stereo(data));
1067 } else
1068 return -EINVAL ;
1069 break ;
1070 case SOUND_PCM_WRITE_CHANNELS:
1071 if (shared_resources_are_mine(file->f_mode) &&
1072 queues_are_quiescent()) {
1073 IOCTL_IN(arg, data);
1074
1075 shared_resources_initialised = 0 ;
1076 return IOCTL_OUT(arg, sound_set_stereo(data-1)+1);
1077 } else
1078 return -EINVAL ;
1079 break ;
1080 case SNDCTL_DSP_SETFMT:
1081 if (shared_resources_are_mine(file->f_mode) &&
1082 queues_are_quiescent()) {
1083 int format;
1084 IOCTL_IN(arg, data);
1085 shared_resources_initialised = 0 ;
1086 format = sound_set_format(data);
1087 result = IOCTL_OUT(arg, format);
1088 if (result < 0)
1089 return result;
1090 if (format != data && data != AFMT_QUERY)
1091 return -EINVAL;
1092 return 0;
1093 } else
1094 return -EINVAL ;
1095 case SNDCTL_DSP_SUBDIVIDE:
1096 return -EINVAL ;
1097 case SNDCTL_DSP_SETFRAGMENT:
1098
1099
1100
1101
1102
1103
1104 IOCTL_IN(arg, data);
1105 result = 0 ;
1106 nbufs = (data >> 16) & 0x7fff ;
1107 size = data & 0xffff;
1108 if (file->f_mode & FMODE_WRITE) {
1109 result = set_queue_frags(&write_sq, nbufs, size) ;
1110 if (result)
1111 return result ;
1112 }
1113
1114
1115
1116 return IOCTL_OUT(arg, data);
1117 case SNDCTL_DSP_GETOSPACE:
1118
1119
1120 if (file->f_mode & FMODE_WRITE) {
1121 if ( !write_sq.locked )
1122 sq_setup(&write_sq) ;
1123 info.fragments = write_sq.max_active - write_sq.count;
1124 info.fragstotal = write_sq.max_active;
1125 info.fragsize = write_sq.user_frag_size;
1126 info.bytes = info.fragments * info.fragsize;
1127 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1128 return -EFAULT;
1129 return 0;
1130 } else
1131 return -EINVAL ;
1132 break ;
1133 case SNDCTL_DSP_GETCAPS:
1134 val = dmasound.mach.capabilities & 0xffffff00;
1135 return IOCTL_OUT(arg,val);
1136
1137 default:
1138 return mixer_ioctl(file, cmd, arg);
1139 }
1140 return -EINVAL;
1141 }
1142
1143 static long sq_unlocked_ioctl(struct file *file, u_int cmd, u_long arg)
1144 {
1145 int ret;
1146
1147 mutex_lock(&dmasound_core_mutex);
1148 ret = sq_ioctl(file, cmd, arg);
1149 mutex_unlock(&dmasound_core_mutex);
1150
1151 return ret;
1152 }
1153
1154 static const struct file_operations sq_fops =
1155 {
1156 .owner = THIS_MODULE,
1157 .llseek = no_llseek,
1158 .write = sq_write,
1159 .poll = sq_poll,
1160 .unlocked_ioctl = sq_unlocked_ioctl,
1161 .compat_ioctl = compat_ptr_ioctl,
1162 .open = sq_open,
1163 .release = sq_release,
1164 };
1165
1166 static int sq_init(void)
1167 {
1168 const struct file_operations *fops = &sq_fops;
1169
1170 sq_unit = register_sound_dsp(fops, -1);
1171 if (sq_unit < 0) {
1172 printk(KERN_ERR "dmasound_core: couldn't register fops\n") ;
1173 return sq_unit ;
1174 }
1175
1176 write_sq_init_waitqueue();
1177
1178
1179
1180
1181
1182
1183 if (shared_resource_owner == 0) {
1184 dmasound.soft = dmasound.mach.default_soft ;
1185 dmasound.hard = dmasound.mach.default_hard ;
1186 dmasound.dsp = dmasound.mach.default_soft ;
1187 shared_resources_initialised = 0 ;
1188 }
1189 return 0 ;
1190 }
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202 #define STAT_BUFF_LEN 768
1203
1204
1205
1206
1207
1208
1209 #define LOW_LEVEL_STAT_ALLOC 162
1210
1211 static struct {
1212 int busy;
1213 char buf[STAT_BUFF_LEN];
1214 int len, ptr;
1215 } state;
1216
1217
1218
1219 static char *get_afmt_string(int afmt)
1220 {
1221 switch(afmt) {
1222 case AFMT_MU_LAW:
1223 return "mu-law";
1224 case AFMT_A_LAW:
1225 return "A-law";
1226 case AFMT_U8:
1227 return "unsigned 8 bit";
1228 case AFMT_S8:
1229 return "signed 8 bit";
1230 case AFMT_S16_BE:
1231 return "signed 16 bit BE";
1232 case AFMT_U16_BE:
1233 return "unsigned 16 bit BE";
1234 case AFMT_S16_LE:
1235 return "signed 16 bit LE";
1236 case AFMT_U16_LE:
1237 return "unsigned 16 bit LE";
1238 case 0:
1239 return "format not set" ;
1240 default:
1241 break ;
1242 }
1243 return "ERROR: Unsupported AFMT_XXXX code" ;
1244 }
1245
1246 static int state_open(struct inode *inode, struct file *file)
1247 {
1248 char *buffer = state.buf;
1249 int len = 0;
1250 int ret;
1251
1252 mutex_lock(&dmasound_core_mutex);
1253 ret = -EBUSY;
1254 if (state.busy)
1255 goto out;
1256
1257 ret = -ENODEV;
1258 if (!try_module_get(dmasound.mach.owner))
1259 goto out;
1260
1261 state.ptr = 0;
1262 state.busy = 1;
1263
1264 len += sprintf(buffer+len, "%sDMA sound driver rev %03d :\n",
1265 dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) +
1266 ((dmasound.mach.version>>8) & 0x0f));
1267 len += sprintf(buffer+len,
1268 "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n",
1269 DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2,
1270 (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
1271
1272
1273
1274
1275
1276 if (dmasound.mach.state_info)
1277 len += dmasound.mach.state_info(buffer+len,
1278 (size_t) LOW_LEVEL_STAT_ALLOC) ;
1279
1280
1281
1282
1283
1284
1285
1286
1287 len += sprintf(buffer+len,"\t\t === Formats & settings ===\n") ;
1288 len += sprintf(buffer+len,"Parameter %20s%20s\n","soft","hard") ;
1289 len += sprintf(buffer+len,"Format :%20s%20s\n",
1290 get_afmt_string(dmasound.soft.format),
1291 get_afmt_string(dmasound.hard.format));
1292
1293 len += sprintf(buffer+len,"Samp Rate:%14d s/sec%14d s/sec\n",
1294 dmasound.soft.speed, dmasound.hard.speed);
1295
1296 len += sprintf(buffer+len,"Channels :%20s%20s\n",
1297 dmasound.soft.stereo ? "stereo" : "mono",
1298 dmasound.hard.stereo ? "stereo" : "mono" );
1299
1300
1301
1302 len += sprintf(buffer+len,"\t\t === Sound Queue status ===\n");
1303 len += sprintf(buffer+len,"Allocated:%8s%6s\n","Buffers","Size") ;
1304 len += sprintf(buffer+len,"%9s:%8d%6d\n",
1305 "write", write_sq.numBufs, write_sq.bufSize) ;
1306 len += sprintf(buffer+len,
1307 "Current : MaxFrg FragSiz MaxAct Frnt Rear "
1308 "Cnt RrSize A B S L xruns\n") ;
1309 len += sprintf(buffer+len,"%9s:%7d%8d%7d%5d%5d%4d%7d%2d%2d%2d%2d%7d\n",
1310 "write", write_sq.max_count, write_sq.block_size,
1311 write_sq.max_active, write_sq.front, write_sq.rear,
1312 write_sq.count, write_sq.rear_size, write_sq.active,
1313 write_sq.busy, write_sq.syncing, write_sq.locked, write_sq.xruns) ;
1314 #ifdef DEBUG_DMASOUND
1315 printk("dmasound: stat buffer used %d bytes\n", len) ;
1316 #endif
1317
1318 if (len >= STAT_BUFF_LEN)
1319 printk(KERN_ERR "dmasound_core: stat buffer overflowed!\n");
1320
1321 state.len = len;
1322 ret = 0;
1323 out:
1324 mutex_unlock(&dmasound_core_mutex);
1325 return ret;
1326 }
1327
1328 static int state_release(struct inode *inode, struct file *file)
1329 {
1330 mutex_lock(&dmasound_core_mutex);
1331 state.busy = 0;
1332 module_put(dmasound.mach.owner);
1333 mutex_unlock(&dmasound_core_mutex);
1334 return 0;
1335 }
1336
1337 static ssize_t state_read(struct file *file, char __user *buf, size_t count,
1338 loff_t *ppos)
1339 {
1340 int n = state.len - state.ptr;
1341 if (n > count)
1342 n = count;
1343 if (n <= 0)
1344 return 0;
1345 if (copy_to_user(buf, &state.buf[state.ptr], n))
1346 return -EFAULT;
1347 state.ptr += n;
1348 return n;
1349 }
1350
1351 static const struct file_operations state_fops = {
1352 .owner = THIS_MODULE,
1353 .llseek = no_llseek,
1354 .read = state_read,
1355 .open = state_open,
1356 .release = state_release,
1357 };
1358
1359 static int state_init(void)
1360 {
1361 state_unit = register_sound_special(&state_fops, SND_DEV_STATUS);
1362 if (state_unit < 0)
1363 return state_unit ;
1364 state.busy = 0;
1365 return 0 ;
1366 }
1367
1368
1369
1370
1371
1372
1373
1374
1375 int dmasound_init(void)
1376 {
1377 int res ;
1378
1379 if (irq_installed)
1380 return -EBUSY;
1381
1382
1383
1384
1385 if ((res = sq_init()) < 0)
1386 return res ;
1387
1388
1389 if ((res = state_init()) < 0)
1390 return res ;
1391
1392
1393 mixer_init();
1394
1395 if (!dmasound.mach.irqinit()) {
1396 printk(KERN_ERR "DMA sound driver: Interrupt initialization failed\n");
1397 return -ENODEV;
1398 }
1399 irq_installed = 1;
1400
1401 printk(KERN_INFO "%s DMA sound driver rev %03d installed\n",
1402 dmasound.mach.name, (DMASOUND_CORE_REVISION<<4) +
1403 ((dmasound.mach.version>>8) & 0x0f));
1404 printk(KERN_INFO
1405 "Core driver edition %02d.%02d : %s driver edition %02d.%02d\n",
1406 DMASOUND_CORE_REVISION, DMASOUND_CORE_EDITION, dmasound.mach.name2,
1407 (dmasound.mach.version >> 8), (dmasound.mach.version & 0xff)) ;
1408 printk(KERN_INFO "Write will use %4d fragments of %7d bytes as default\n",
1409 numWriteBufs, writeBufSize) ;
1410 return 0;
1411 }
1412
1413 void dmasound_deinit(void)
1414 {
1415 if (irq_installed) {
1416 sound_silence();
1417 dmasound.mach.irqcleanup();
1418 irq_installed = 0;
1419 }
1420
1421 write_sq_release_buffers();
1422
1423 if (mixer_unit >= 0)
1424 unregister_sound_mixer(mixer_unit);
1425 if (state_unit >= 0)
1426 unregister_sound_special(state_unit);
1427 if (sq_unit >= 0)
1428 unregister_sound_dsp(sq_unit);
1429 }
1430
1431 static int __maybe_unused dmasound_setup(char *str)
1432 {
1433 int ints[6], size;
1434
1435 str = get_options(str, ARRAY_SIZE(ints), ints);
1436
1437
1438
1439
1440
1441
1442
1443 switch (ints[0]) {
1444 case 3:
1445 if ((ints[3] < 0) || (ints[3] > MAX_CATCH_RADIUS))
1446 printk("dmasound_setup: invalid catch radius, using default = %d\n", catchRadius);
1447 else
1448 catchRadius = ints[3];
1449 fallthrough;
1450 case 2:
1451 if (ints[1] < MIN_BUFFERS)
1452 printk("dmasound_setup: invalid number of buffers, using default = %d\n", numWriteBufs);
1453 else
1454 numWriteBufs = ints[1];
1455 fallthrough;
1456 case 1:
1457 if ((size = ints[2]) < 256)
1458 size <<= 10 ;
1459 if (size < MIN_BUFSIZE || size > MAX_BUFSIZE)
1460 printk("dmasound_setup: invalid write buffer size, using default = %d\n", writeBufSize);
1461 else
1462 writeBufSize = size;
1463 case 0:
1464 break;
1465 default:
1466 printk("dmasound_setup: invalid number of arguments\n");
1467 return 0;
1468 }
1469 return 1;
1470 }
1471
1472 __setup("dmasound=", dmasound_setup);
1473
1474
1475
1476
1477
1478 #ifdef HAS_8BIT_TABLES
1479
1480
1481 char dmasound_ulaw2dma8[] = {
1482 -126, -122, -118, -114, -110, -106, -102, -98,
1483 -94, -90, -86, -82, -78, -74, -70, -66,
1484 -63, -61, -59, -57, -55, -53, -51, -49,
1485 -47, -45, -43, -41, -39, -37, -35, -33,
1486 -31, -30, -29, -28, -27, -26, -25, -24,
1487 -23, -22, -21, -20, -19, -18, -17, -16,
1488 -16, -15, -15, -14, -14, -13, -13, -12,
1489 -12, -11, -11, -10, -10, -9, -9, -8,
1490 -8, -8, -7, -7, -7, -7, -6, -6,
1491 -6, -6, -5, -5, -5, -5, -4, -4,
1492 -4, -4, -4, -4, -3, -3, -3, -3,
1493 -3, -3, -3, -3, -2, -2, -2, -2,
1494 -2, -2, -2, -2, -2, -2, -2, -2,
1495 -1, -1, -1, -1, -1, -1, -1, -1,
1496 -1, -1, -1, -1, -1, -1, -1, -1,
1497 -1, -1, -1, -1, -1, -1, -1, 0,
1498 125, 121, 117, 113, 109, 105, 101, 97,
1499 93, 89, 85, 81, 77, 73, 69, 65,
1500 62, 60, 58, 56, 54, 52, 50, 48,
1501 46, 44, 42, 40, 38, 36, 34, 32,
1502 30, 29, 28, 27, 26, 25, 24, 23,
1503 22, 21, 20, 19, 18, 17, 16, 15,
1504 15, 14, 14, 13, 13, 12, 12, 11,
1505 11, 10, 10, 9, 9, 8, 8, 7,
1506 7, 7, 6, 6, 6, 6, 5, 5,
1507 5, 5, 4, 4, 4, 4, 3, 3,
1508 3, 3, 3, 3, 2, 2, 2, 2,
1509 2, 2, 2, 2, 1, 1, 1, 1,
1510 1, 1, 1, 1, 1, 1, 1, 1,
1511 0, 0, 0, 0, 0, 0, 0, 0,
1512 0, 0, 0, 0, 0, 0, 0, 0,
1513 0, 0, 0, 0, 0, 0, 0, 0
1514 };
1515
1516
1517
1518 char dmasound_alaw2dma8[] = {
1519 -22, -21, -24, -23, -18, -17, -20, -19,
1520 -30, -29, -32, -31, -26, -25, -28, -27,
1521 -11, -11, -12, -12, -9, -9, -10, -10,
1522 -15, -15, -16, -16, -13, -13, -14, -14,
1523 -86, -82, -94, -90, -70, -66, -78, -74,
1524 -118, -114, -126, -122, -102, -98, -110, -106,
1525 -43, -41, -47, -45, -35, -33, -39, -37,
1526 -59, -57, -63, -61, -51, -49, -55, -53,
1527 -2, -2, -2, -2, -2, -2, -2, -2,
1528 -2, -2, -2, -2, -2, -2, -2, -2,
1529 -1, -1, -1, -1, -1, -1, -1, -1,
1530 -1, -1, -1, -1, -1, -1, -1, -1,
1531 -6, -6, -6, -6, -5, -5, -5, -5,
1532 -8, -8, -8, -8, -7, -7, -7, -7,
1533 -3, -3, -3, -3, -3, -3, -3, -3,
1534 -4, -4, -4, -4, -4, -4, -4, -4,
1535 21, 20, 23, 22, 17, 16, 19, 18,
1536 29, 28, 31, 30, 25, 24, 27, 26,
1537 10, 10, 11, 11, 8, 8, 9, 9,
1538 14, 14, 15, 15, 12, 12, 13, 13,
1539 86, 82, 94, 90, 70, 66, 78, 74,
1540 118, 114, 126, 122, 102, 98, 110, 106,
1541 43, 41, 47, 45, 35, 33, 39, 37,
1542 59, 57, 63, 61, 51, 49, 55, 53,
1543 1, 1, 1, 1, 1, 1, 1, 1,
1544 1, 1, 1, 1, 1, 1, 1, 1,
1545 0, 0, 0, 0, 0, 0, 0, 0,
1546 0, 0, 0, 0, 0, 0, 0, 0,
1547 5, 5, 5, 5, 4, 4, 4, 4,
1548 7, 7, 7, 7, 6, 6, 6, 6,
1549 2, 2, 2, 2, 2, 2, 2, 2,
1550 3, 3, 3, 3, 3, 3, 3, 3
1551 };
1552 #endif
1553
1554
1555
1556
1557
1558 EXPORT_SYMBOL(dmasound);
1559 EXPORT_SYMBOL(dmasound_init);
1560 EXPORT_SYMBOL(dmasound_deinit);
1561 EXPORT_SYMBOL(dmasound_write_sq);
1562 EXPORT_SYMBOL(dmasound_catchRadius);
1563 #ifdef HAS_8BIT_TABLES
1564 EXPORT_SYMBOL(dmasound_ulaw2dma8);
1565 EXPORT_SYMBOL(dmasound_alaw2dma8);
1566 #endif