diff options
| author | augustss <augustss@NetBSD.org> | 1997-07-27 01:16:32 +0000 |
|---|---|---|
| committer | augustss <augustss@NetBSD.org> | 1997-07-27 01:16:32 +0000 |
| commit | 9745684ebe151a825bdef45d38da2ef82fc893d1 (patch) | |
| tree | 9fc1a39eeab95505d742a8f6fe2003dc0381e354 /sys | |
| parent | 3ca46d33e107a26b997c048032ddeacf5270b46f (diff) | |
Changes to the sudio system:
- It is now possible to handle devices that want "looping" DMA,
e.g. the SoundBlaster correctly. The WSS and SB drivers use this.
To do this several new methods were introduced in audio_hw_if.
- Different silence handling (forced by previous change).
- The audio driver can now be mmap()-ed, but due to problems in
the VM system only for writing for now.
- The OSS (Linux) audio emulation takes advantage of some of the
new features.
Diffstat (limited to 'sys')
41 files changed, 1532 insertions, 826 deletions
diff --git a/sys/arch/arm32/mainbus/lmcaudio.c b/sys/arch/arm32/mainbus/lmcaudio.c index 64d3985b43a..8c0f6f4c1ad 100644 --- a/sys/arch/arm32/mainbus/lmcaudio.c +++ b/sys/arch/arm32/mainbus/lmcaudio.c @@ -1,4 +1,4 @@ -/* $NetBSD: lmcaudio.c,v 1.8 1997/07/15 07:46:07 augustss Exp $ */ +/* $NetBSD: lmcaudio.c,v 1.9 1997/07/27 01:16:32 augustss Exp $ */ /* * Copyright (c) 1996, Danny C Tsen. @@ -613,6 +613,8 @@ struct audio_hw_if lmcaudio_hw_if = { lmcaudio_set_in_port, lmcaudio_get_in_port, lmcaudio_commit_settings, + NULL, + NULL, lmcaudio_start_output, lmcaudio_start_input, lmcaudio_halt_output, @@ -625,7 +627,10 @@ struct audio_hw_if lmcaudio_hw_if = { lmcaudio_set_port, lmcaudio_get_port, lmcaudio_query_devinfo, - 0, /* not full duplex */ + 0, + 0, + 0, + 0, 0 }; diff --git a/sys/arch/arm32/mainbus/vidcaudio.c b/sys/arch/arm32/mainbus/vidcaudio.c index 0f8d888bb4b..55a453b3d81 100644 --- a/sys/arch/arm32/mainbus/vidcaudio.c +++ b/sys/arch/arm32/mainbus/vidcaudio.c @@ -1,4 +1,4 @@ -/* $NetBSD: vidcaudio.c,v 1.13 1997/05/09 22:16:28 augustss Exp $ */ +/* $NetBSD: vidcaudio.c,v 1.14 1997/07/27 01:16:34 augustss Exp $ */ /* * Copyright (c) 1995 Melvin Tang-Richardson @@ -519,6 +519,8 @@ struct audio_hw_if vidcaudio_hw_if = { vidcaudio_set_in_port, vidcaudio_get_in_port, vidcaudio_commit_settings, + NULL, + NULL, vidcaudio_start_output, vidcaudio_start_input, vidcaudio_halt_output, @@ -531,7 +533,10 @@ struct audio_hw_if vidcaudio_hw_if = { vidcaudio_set_port, vidcaudio_get_port, vidcaudio_query_devinfo, - 0, /* not full duplex */ + 0, + 0, + 0, + 0, 0 }; diff --git a/sys/arch/arm32/vidc/lmcaudio.c b/sys/arch/arm32/vidc/lmcaudio.c index 64d3985b43a..8c0f6f4c1ad 100644 --- a/sys/arch/arm32/vidc/lmcaudio.c +++ b/sys/arch/arm32/vidc/lmcaudio.c @@ -1,4 +1,4 @@ -/* $NetBSD: lmcaudio.c,v 1.8 1997/07/15 07:46:07 augustss Exp $ */ +/* $NetBSD: lmcaudio.c,v 1.9 1997/07/27 01:16:32 augustss Exp $ */ /* * Copyright (c) 1996, Danny C Tsen. @@ -613,6 +613,8 @@ struct audio_hw_if lmcaudio_hw_if = { lmcaudio_set_in_port, lmcaudio_get_in_port, lmcaudio_commit_settings, + NULL, + NULL, lmcaudio_start_output, lmcaudio_start_input, lmcaudio_halt_output, @@ -625,7 +627,10 @@ struct audio_hw_if lmcaudio_hw_if = { lmcaudio_set_port, lmcaudio_get_port, lmcaudio_query_devinfo, - 0, /* not full duplex */ + 0, + 0, + 0, + 0, 0 }; diff --git a/sys/arch/arm32/vidc/vidcaudio.c b/sys/arch/arm32/vidc/vidcaudio.c index 0f8d888bb4b..55a453b3d81 100644 --- a/sys/arch/arm32/vidc/vidcaudio.c +++ b/sys/arch/arm32/vidc/vidcaudio.c @@ -1,4 +1,4 @@ -/* $NetBSD: vidcaudio.c,v 1.13 1997/05/09 22:16:28 augustss Exp $ */ +/* $NetBSD: vidcaudio.c,v 1.14 1997/07/27 01:16:34 augustss Exp $ */ /* * Copyright (c) 1995 Melvin Tang-Richardson @@ -519,6 +519,8 @@ struct audio_hw_if vidcaudio_hw_if = { vidcaudio_set_in_port, vidcaudio_get_in_port, vidcaudio_commit_settings, + NULL, + NULL, vidcaudio_start_output, vidcaudio_start_input, vidcaudio_halt_output, @@ -531,7 +533,10 @@ struct audio_hw_if vidcaudio_hw_if = { vidcaudio_set_port, vidcaudio_get_port, vidcaudio_query_devinfo, - 0, /* not full duplex */ + 0, + 0, + 0, + 0, 0 }; diff --git a/sys/arch/sparc/dev/am7930_sparc.c b/sys/arch/sparc/dev/am7930_sparc.c index af313ada717..0dfb9879cf2 100644 --- a/sys/arch/sparc/dev/am7930_sparc.c +++ b/sys/arch/sparc/dev/am7930_sparc.c @@ -1,4 +1,4 @@ -/* $NetBSD: am7930_sparc.c,v 1.22 1997/05/24 20:15:59 pk Exp $ */ +/* $NetBSD: am7930_sparc.c,v 1.23 1997/07/27 01:16:37 augustss Exp $ */ /* * Copyright (c) 1995 Rolf Grossmann @@ -240,6 +240,8 @@ struct audio_hw_if sa_hw_if = { amd7930_set_in_port, amd7930_get_in_port, amd7930_commit_settings, + NULL, + NULL, amd7930_start_output, amd7930_start_input, amd7930_halt_output, @@ -252,7 +254,10 @@ struct audio_hw_if sa_hw_if = { amd7930_set_port, amd7930_get_port, amd7930_query_devinfo, - 1, + 0, + 0, + 0, + AUDIO_PROP_FULLDUPLEX, 0 }; diff --git a/sys/arch/sparc/dev/amd7930.c b/sys/arch/sparc/dev/amd7930.c index 85193e5051b..7a27e509f56 100644 --- a/sys/arch/sparc/dev/amd7930.c +++ b/sys/arch/sparc/dev/amd7930.c @@ -1,4 +1,4 @@ -/* $NetBSD: amd7930.c,v 1.22 1997/05/24 20:15:59 pk Exp $ */ +/* $NetBSD: amd7930.c,v 1.23 1997/07/27 01:16:37 augustss Exp $ */ /* * Copyright (c) 1995 Rolf Grossmann @@ -240,6 +240,8 @@ struct audio_hw_if sa_hw_if = { amd7930_set_in_port, amd7930_get_in_port, amd7930_commit_settings, + NULL, + NULL, amd7930_start_output, amd7930_start_input, amd7930_halt_output, @@ -252,7 +254,10 @@ struct audio_hw_if sa_hw_if = { amd7930_set_port, amd7930_get_port, amd7930_query_devinfo, - 1, + 0, + 0, + 0, + AUDIO_PROP_FULLDUPLEX, 0 }; diff --git a/sys/compat/linux/common/linux_break.c b/sys/compat/linux/common/linux_break.c index 5643cccbd6c..f59e68ab0ff 100644 --- a/sys/compat/linux/common/linux_break.c +++ b/sys/compat/linux/common/linux_break.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_break.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_break.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_misc.c b/sys/compat/linux/common/linux_misc.c index ba0a5f94d32..689533b9686 100644 --- a/sys/compat/linux/common/linux_misc.c +++ b/sys/compat/linux/common/linux_misc.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_misc.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_misc.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_misc_notalpha.c b/sys/compat/linux/common/linux_misc_notalpha.c index 9c21bf6697a..c9652801653 100644 --- a/sys/compat/linux/common/linux_misc_notalpha.c +++ b/sys/compat/linux/common/linux_misc_notalpha.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_misc_notalpha.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_misc_notalpha.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_oldmmap.c b/sys/compat/linux/common/linux_oldmmap.c index 2439368527b..fa194714b6c 100644 --- a/sys/compat/linux/common/linux_oldmmap.c +++ b/sys/compat/linux/common/linux_oldmmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_oldmmap.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_oldmmap.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_oldolduname.c b/sys/compat/linux/common/linux_oldolduname.c index 5a85237cea9..36620118a18 100644 --- a/sys/compat/linux/common/linux_oldolduname.c +++ b/sys/compat/linux/common/linux_oldolduname.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_oldolduname.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_oldolduname.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_oldselect.c b/sys/compat/linux/common/linux_oldselect.c index 32b1690d8fe..c874ae6be61 100644 --- a/sys/compat/linux/common/linux_oldselect.c +++ b/sys/compat/linux/common/linux_oldselect.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_oldselect.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_oldselect.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_olduname.c b/sys/compat/linux/common/linux_olduname.c index c7e9991ca5c..3fa73008ebc 100644 --- a/sys/compat/linux/common/linux_olduname.c +++ b/sys/compat/linux/common/linux_olduname.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_olduname.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_olduname.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/common/linux_pipe.c b/sys/compat/linux/common/linux_pipe.c index a5b7f6e68a2..df524698e17 100644 --- a/sys/compat/linux/common/linux_pipe.c +++ b/sys/compat/linux/common/linux_pipe.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_pipe.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_pipe.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c index ba0a5f94d32..689533b9686 100644 --- a/sys/compat/linux/linux_misc.c +++ b/sys/compat/linux/linux_misc.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_misc.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_misc.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_break.c b/sys/compat/linux/multiarch/linux_break.c index 5643cccbd6c..f59e68ab0ff 100644 --- a/sys/compat/linux/multiarch/linux_break.c +++ b/sys/compat/linux/multiarch/linux_break.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_break.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_break.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_misc_notalpha.c b/sys/compat/linux/multiarch/linux_misc_notalpha.c index 9c21bf6697a..c9652801653 100644 --- a/sys/compat/linux/multiarch/linux_misc_notalpha.c +++ b/sys/compat/linux/multiarch/linux_misc_notalpha.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_misc_notalpha.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_misc_notalpha.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_oldmmap.c b/sys/compat/linux/multiarch/linux_oldmmap.c index 2439368527b..fa194714b6c 100644 --- a/sys/compat/linux/multiarch/linux_oldmmap.c +++ b/sys/compat/linux/multiarch/linux_oldmmap.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_oldmmap.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_oldmmap.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_oldolduname.c b/sys/compat/linux/multiarch/linux_oldolduname.c index 5a85237cea9..36620118a18 100644 --- a/sys/compat/linux/multiarch/linux_oldolduname.c +++ b/sys/compat/linux/multiarch/linux_oldolduname.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_oldolduname.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_oldolduname.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_oldselect.c b/sys/compat/linux/multiarch/linux_oldselect.c index 32b1690d8fe..c874ae6be61 100644 --- a/sys/compat/linux/multiarch/linux_oldselect.c +++ b/sys/compat/linux/multiarch/linux_oldselect.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_oldselect.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_oldselect.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_olduname.c b/sys/compat/linux/multiarch/linux_olduname.c index c7e9991ca5c..3fa73008ebc 100644 --- a/sys/compat/linux/multiarch/linux_olduname.c +++ b/sys/compat/linux/multiarch/linux_olduname.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_olduname.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_olduname.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/linux/multiarch/linux_pipe.c b/sys/compat/linux/multiarch/linux_pipe.c index a5b7f6e68a2..df524698e17 100644 --- a/sys/compat/linux/multiarch/linux_pipe.c +++ b/sys/compat/linux/multiarch/linux_pipe.c @@ -1,4 +1,4 @@ -/* $NetBSD: linux_pipe.c,v 1.30 1997/04/07 14:13:16 augustss Exp $ */ +/* $NetBSD: linux_pipe.c,v 1.31 1997/07/27 01:16:39 augustss Exp $ */ /* * Copyright (c) 1995 Frank van der Linden @@ -502,6 +502,8 @@ linux_sys_mmap(p, v, retval) SCARG(&cma,addr) = lmap.lm_addr; SCARG(&cma,len) = lmap.lm_len; + if (lmap.lm_prot & VM_PROT_WRITE) /* XXX */ + lmap.lm_prot |= VM_PROT_READ; SCARG(&cma,prot) = lmap.lm_prot; SCARG(&cma,flags) = flags; SCARG(&cma,fd) = lmap.lm_fd; diff --git a/sys/compat/ossaudio/ossaudio.c b/sys/compat/ossaudio/ossaudio.c index adaa271ef8c..cfe8a0f354c 100644 --- a/sys/compat/ossaudio/ossaudio.c +++ b/sys/compat/ossaudio/ossaudio.c @@ -1,4 +1,4 @@ -/* $NetBSD: ossaudio.c,v 1.12 1997/07/15 07:46:09 augustss Exp $ */ +/* $NetBSD: ossaudio.c,v 1.13 1997/07/27 01:16:41 augustss Exp $ */ #include <sys/param.h> #include <sys/proc.h> #include <sys/systm.h> @@ -30,7 +30,10 @@ oss_ioctl_audio(p, uap, retval) register struct filedesc *fdp; u_long com; struct audio_info tmpinfo; - int idat; + struct audio_offset tmpoffs; + struct oss_audio_buf_info bufinfo; + struct oss_count_info cntinfo; + int idat, idata; int error; int (*ioctlf) __P((struct file *, u_long, caddr_t, struct proc *)); @@ -270,19 +273,85 @@ oss_ioctl_audio(p, uap, retval) return error; break; case OSS_SNDCTL_DSP_GETOSPACE: + error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); + if (error) + return error; + bufinfo.fragsize = tmpinfo.blocksize; + bufinfo.fragments = /* XXX */ + bufinfo.fragstotal = tmpinfo.buffersize / bufinfo.fragsize; + bufinfo.bytes = bufinfo.fragments * bufinfo.fragsize; + error = copyout(&bufinfo, SCARG(uap, data), sizeof bufinfo); + if (error) + return error; + break; case OSS_SNDCTL_DSP_GETISPACE: case OSS_SNDCTL_DSP_NONBLOCK: return EINVAL; /* XXX unimplemented */ case OSS_SNDCTL_DSP_GETCAPS: - idat = 0; /* XXX full duplex info should be set */ + error = ioctlf(fp, AUDIO_GETPROPS, (caddr_t)&idata, p); + if (error) + return error; + idat = OSS_DSP_CAP_TRIGGER; /* pretend we have trigger */ + if (idata & AUDIO_PROP_FULLDUPLEX) + idat |= OSS_DSP_CAP_DUPLEX; + if (idata & AUDIO_PROP_MMAP) + idat |= OSS_DSP_CAP_MMAP; error = copyout(&idat, SCARG(uap, data), sizeof idat); if (error) return error; break; +#if 0 case OSS_SNDCTL_DSP_GETTRIGGER: + error = ioctlf(fp, AUDIO_GETINFO, (caddr_t)&tmpinfo, p); + if (error) + return error; + idat = (tmpinfo.play.pause ? 0 : OSS_PCM_ENABLE_OUTPUT) | + (tmpinfo.record.pause ? 0 : OSS_PCM_ENABLE_INPUT); + error = copyout(&idat, SCARG(uap, data), sizeof idat); + if (error) + return error; + break; case OSS_SNDCTL_DSP_SETTRIGGER: + AUDIO_INITINFO(&tmpinfo); + error = copyin(SCARG(uap, data), &idat, sizeof idat); + if (error) + return error; + tmpinfo.play.pause = (idat & OSS_PCM_ENABLE_OUTPUT) == 0; + tmpinfo.record.pause = (idat & OSS_PCM_ENABLE_INPUT) == 0; + (void) ioctlf(fp, AUDIO_SETINFO, (caddr_t)&tmpinfo, p); + error = copyout(&idat, SCARG(uap, data), sizeof idat); + if (error) + return error; + break; +#else + case OSS_SNDCTL_DSP_GETTRIGGER: + case OSS_SNDCTL_DSP_SETTRIGGER: + /* XXX Do nothing for now. */ + idat = OSS_PCM_ENABLE_OUTPUT; + return copyout(&idat, SCARG(uap, data), sizeof idat); +#endif case OSS_SNDCTL_DSP_GETIPTR: + error = ioctlf(fp, AUDIO_GETIOFFS, (caddr_t)&tmpoffs, p); + if (error) + return error; + cntinfo.bytes = tmpoffs.samples; + cntinfo.blocks = tmpoffs.deltablks; + cntinfo.ptr = tmpoffs.offset; + error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); + if (error) + return error; + break; case OSS_SNDCTL_DSP_GETOPTR: + error = ioctlf(fp, AUDIO_GETOOFFS, (caddr_t)&tmpoffs, p); + if (error) + return error; + cntinfo.bytes = tmpoffs.samples; + cntinfo.blocks = tmpoffs.deltablks; + cntinfo.ptr = tmpoffs.offset; + error = copyout(&cntinfo, SCARG(uap, data), sizeof cntinfo); + if (error) + return error; + break; case OSS_SNDCTL_DSP_MAPINBUF: case OSS_SNDCTL_DSP_MAPOUTBUF: case OSS_SNDCTL_DSP_SETSYNCRO: diff --git a/sys/compat/ossaudio/ossaudiovar.h b/sys/compat/ossaudio/ossaudiovar.h index 4b8d10dd182..c31bb865e02 100644 --- a/sys/compat/ossaudio/ossaudiovar.h +++ b/sys/compat/ossaudio/ossaudiovar.h @@ -1,4 +1,4 @@ -/* $NetBSD: ossaudiovar.h,v 1.1 1997/04/04 15:36:02 augustss Exp $ */ +/* $NetBSD: ossaudiovar.h,v 1.2 1997/07/27 01:16:42 augustss Exp $ */ struct oss_sys_ioctl_args { syscallarg(int) fd; syscallarg(u_long) com; @@ -16,22 +16,22 @@ struct oss_sys_ioctl_args { #define _OSS_IOW(x,y,t) _OSS_IOCTL(OSS_IOC_IN, x, y, sizeof(t)) #define _OSS_IOWR(x,y,t) _OSS_IOCTL(OSS_IOC_INOUT, x, y, sizeof(t)) -#define OSS_SNDCTL_DSP_RESET _OSS_IO('P', 0) -#define OSS_SNDCTL_DSP_SYNC _OSS_IO('P', 1) +#define OSS_SNDCTL_DSP_RESET _OSS_IO ('P', 0) +#define OSS_SNDCTL_DSP_SYNC _OSS_IO ('P', 1) #define OSS_SNDCTL_DSP_SPEED _OSS_IOWR('P', 2, int) -#define OSS_SOUND_PCM_READ_RATE _OSS_IOR('P', 2, int) +#define OSS_SOUND_PCM_READ_RATE _OSS_IOR ('P', 2, int) #define OSS_SNDCTL_DSP_STEREO _OSS_IOWR('P', 3, int) #define OSS_SNDCTL_DSP_GETBLKSIZE _OSS_IOWR('P', 4, int) #define OSS_SNDCTL_DSP_SETFMT _OSS_IOWR('P', 5, int) -#define OSS_SOUND_PCM_READ_BITS _OSS_IOR('P', 5, int) +#define OSS_SOUND_PCM_READ_BITS _OSS_IOR ('P', 5, int) #define OSS_SNDCTL_DSP_CHANNELS _OSS_IOWR('P', 6, int) -#define OSS_SOUND_PCM_READ_CHANNELS _OSS_IOR('P', 6, int) +#define OSS_SOUND_PCM_READ_CHANNELS _OSS_IOR ('P', 6, int) #define OSS_SOUND_PCM_WRITE_FILTER _OSS_IOWR('P', 7, int) -#define OSS_SOUND_PCM_READ_FILTER _OSS_IOR('P', 7, int) -#define OSS_SNDCTL_DSP_POST _OSS_IO('P', 8) +#define OSS_SOUND_PCM_READ_FILTER _OSS_IOR ('P', 7, int) +#define OSS_SNDCTL_DSP_POST _OSS_IO ('P', 8) #define OSS_SNDCTL_DSP_SUBDIVIDE _OSS_IOWR('P', 9, int) #define OSS_SNDCTL_DSP_SETFRAGMENT _OSS_IOWR('P', 10, int) -#define OSS_SNDCTL_DSP_GETFMTS _OSS_IOR('P', 11, int) +#define OSS_SNDCTL_DSP_GETFMTS _OSS_IOR ('P', 11, int) #define OSS_SNDCTL_DSP_GETOSPACE _OSS_IOR ('P',12, struct oss_audio_buf_info) #define OSS_SNDCTL_DSP_GETISPACE _OSS_IOR ('P',13, struct oss_audio_buf_info) #define OSS_SNDCTL_DSP_NONBLOCK _OSS_IO ('P',14) @@ -43,10 +43,12 @@ struct oss_sys_ioctl_args { # define OSS_DSP_CAP_COPROC 0x00000800 # define OSS_DSP_CAP_TRIGGER 0x00001000 # define OSS_DSP_CAP_MMAP 0x00002000 -#define OSS_SNDCTL_DSP_GETTRIGGER _OSS_IOR ('P',16, int) -#define OSS_SNDCTL_DSP_SETTRIGGER _OSS_IOW ('P',16, int) -#define OSS_SNDCTL_DSP_GETIPTR _OSS_IOR ('P',17, struct oss_count_info) -#define OSS_SNDCTL_DSP_GETOPTR _OSS_IOR ('P',18, struct oss_count_info) +#define OSS_SNDCTL_DSP_GETTRIGGER _OSS_IOR ('P', 16, int) +#define OSS_SNDCTL_DSP_SETTRIGGER _OSS_IOW ('P', 16, int) +# define OSS_PCM_ENABLE_INPUT 0x00000001 +# define OSS_PCM_ENABLE_OUTPUT 0x00000002 +#define OSS_SNDCTL_DSP_GETIPTR _OSS_IOR ('P', 17, struct oss_count_info) +#define OSS_SNDCTL_DSP_GETOPTR _OSS_IOR ('P', 18, struct oss_count_info) #define OSS_SNDCTL_DSP_MAPINBUF _OSS_IOR ('P', 19, struct oss_buffmem_desc) #define OSS_SNDCTL_DSP_MAPOUTBUF _OSS_IOR ('P', 20, struct oss_buffmem_desc) #define OSS_SNDCTL_DSP_SETSYNCRO _OSS_IO ('P', 21) diff --git a/sys/dev/audio.c b/sys/dev/audio.c index ea87569be97..9f4f2468b09 100644 --- a/sys/dev/audio.c +++ b/sys/dev/audio.c @@ -1,4 +1,4 @@ -/* $NetBSD: audio.c,v 1.51 1997/07/15 07:46:11 augustss Exp $ */ +/* $NetBSD: audio.c,v 1.52 1997/07/27 01:16:44 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -57,10 +57,7 @@ /* * Todo: * - Add softaudio() isr processing for wakeup, poll and signals. - * - Allow opens for READ and WRITE (one open each) - * - Setup for single isr for full-duplex - * - Add SIGIO generation for changes in the mixer device - * - Fixup SunOS compat for mixer device changes in ioctl. + * - Add SIGIO generation for changes in the mixer device. */ #include "audio.h" @@ -84,37 +81,21 @@ #include <dev/audio_if.h> #include <dev/audiovar.h> +#include <vm/vm.h> +#include <vm/vm_prot.h> + #include <machine/endian.h> #ifdef AUDIO_DEBUG -#include <machine/stdarg.h> - -void Dprintf __P((const char *, ...)); - -void -#ifdef __STDC__ -Dprintf(const char *fmt, ...) -#else -Dprintf(fmt, va_alist) - char *fmt; -#endif -{ - va_list ap; - - va_start(ap, fmt); - log(LOG_DEBUG, "%:", fmt, ap); - va_end(ap); -} - -#define DPRINTF(x) if (audiodebug) Dprintf x +#define DPRINTF(x) if (audiodebug) printf x int audiodebug = 0; #else #define DPRINTF(x) #endif +#define ROUNDSIZE(x) x &= -16 /* round to nice boundary */ int audio_blk_ms = AUDIO_BLK_MS; -int audio_backlog = AUDIO_BACKLOG; struct audio_softc **audio_softc; int naudio = 0; /* Current size of audio_softc */ @@ -140,30 +121,33 @@ void audiostartr __P((struct audio_softc *)); void audiostartp __P((struct audio_softc *)); void audio_rint __P((void *)); void audio_pint __P((void *)); -void audio_rpint __P((void *)); int audio_check_params __P((struct audio_params *)); -int audio_calc_blksize __P((struct audio_softc *)); +void audio_calc_blksize __P((struct audio_softc *, int)); void audio_fill_silence __P((struct audio_params *, u_char *, int)); int audio_silence_copyout __P((struct audio_softc *, int, struct uio *)); -void audio_alloc_auzero __P((struct audio_softc *, int)); -void audio_printsc __P((struct audio_softc *)); -void audioattach __P((int)); int audio_hardware_attach __P((struct audio_hw_if *, void *)); -void audio_init_ring __P((struct audio_buffer *, int)); +void audio_init_ringbuffer __P((struct audio_ringbuffer *)); void audio_initbufs __P((struct audio_softc *)); static __inline int audio_sleep_timo __P((int *, char *, int)); static __inline int audio_sleep __P((int *, char *)); static __inline void audio_wakeup __P((int *)); int audio_drain __P((struct audio_softc *)); void audio_clear __P((struct audio_softc *)); +static __inline void audio_pint_silence __P((struct audio_softc *, struct audio_ringbuffer *, u_char *, int)); + +int audio_alloc_ring __P((struct audio_softc *, struct audio_ringbuffer *, int)); +void audio_free_ring __P((struct audio_softc *, struct audio_ringbuffer *)); /* The default audio mode: 8 kHz mono ulaw */ struct audio_params audio_default = { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0 }; #ifdef AUDIO_DEBUG +void audio_printsc __P((struct audio_softc *)); +void audio_print_params __P((char *, struct audio_params *)); + void audio_printsc(sc) struct audio_softc *sc; @@ -171,19 +155,58 @@ audio_printsc(sc) printf("hwhandle %p hw_if %p ", sc->hw_hdl, sc->hw_if); printf("open %x mode %x\n", sc->sc_open, sc->sc_mode); printf("rchan %x wchan %x ", sc->sc_rchan, sc->sc_wchan); - printf("rring blk %x pring nblk %x\n", sc->rr.nblk, sc->pr.nblk); + printf("rring used %x pring used=%d\n", sc->sc_rr.used, sc->sc_pr.used); printf("rbus %x pbus %x ", sc->sc_rbus, sc->sc_pbus); - printf("blksz %d sib %d ", sc->sc_blksize, sc->sc_smpl_in_blk); - printf("sp50ms %d backlog %d\n", sc->sc_50ms, sc->sc_backlog); - printf("hiwat %d lowat %d rblks %d\n", sc->sc_hiwat, sc->sc_lowat, - sc->sc_rblks); + printf("blksize %d", sc->sc_pr.blksize); + printf("hiwat %d lowat %d\n", sc->sc_pr.usedhigh, sc->sc_pr.usedlow); +} + +void +audio_print_params(s, p) + char *s; + struct audio_params *p; +{ + printf("audio: %s sr=%ld, enc=%d, chan=%d, prec=%d\n", s, + p->sample_rate, p->encoding, p->channels, p->precision); } #endif +int +audio_alloc_ring(sc, r, bufsize) + struct audio_softc *sc; + struct audio_ringbuffer *r; + int bufsize; +{ + struct audio_hw_if *hw = sc->hw_if; + void *hdl = sc->hw_hdl; + /* + * Alloc DMA play and record buffers + */ + ROUNDSIZE(bufsize); + if (bufsize < AUMINBUF) + bufsize = AUMINBUF; + if (hw->roundbuffer) + bufsize = hw->roundbuffer(hdl, bufsize); + r->bufsize = bufsize; + if (hw->alloc) + r->start = hw->alloc(hdl, r->bufsize, M_DEVBUF, M_WAITOK); + else + r->start = malloc(bufsize, M_DEVBUF, M_WAITOK); + if (r->start == 0) + return ENOMEM; + return 0; +} + void -audioattach(num) - int num; +audio_free_ring(sc, r) + struct audio_softc *sc; + struct audio_ringbuffer *r; { + if (sc->hw_if->free) { + sc->hw_if->free(sc->hw_hdl, r->start, M_DEVBUF); + } else { + free(r->start, M_DEVBUF); + } } /* @@ -195,6 +218,7 @@ audio_hardware_attach(hwp, hdlp) void *hdlp; { struct audio_softc *sc; + int error; int n; /* Find a free slot. */ @@ -207,10 +231,10 @@ audio_hardware_attach(hwp, hdlp) naudio++; new = malloc(naudio * sizeof(struct audio_softc *), M_DEVBUF, M_WAITOK); - bcopy(audio_softc, new, - n * sizeof(struct audio_softc *)); - if (audio_softc) + if (audio_softc) { + bcopy(audio_softc, new, n * sizeof(struct audio_softc *)); free(audio_softc, M_DEVBUF); + } audio_softc = new; audio_softc[n] = 0; } @@ -219,8 +243,9 @@ audio_hardware_attach(hwp, hdlp) sc = malloc(sizeof(struct audio_softc), M_DEVBUF, M_WAITOK); bzero(sc, sizeof(struct audio_softc)); - /* XXX too paranoid? */ - if (hwp->open == 0 || +#ifdef DIAGNOSTIC + if (hwp == 0 || + hwp->open == 0 || hwp->close == 0 || hwp->query_encoding == 0 || hwp->set_params == 0 || @@ -243,25 +268,20 @@ audio_hardware_attach(hwp, hdlp) free(sc, M_DEVBUF); return(EINVAL); } +#endif sc->hw_if = hwp; sc->hw_hdl = hdlp; - - /* - * Alloc DMA play and record buffers - */ - sc->rr.bp = malloc(AU_RING_SIZE, M_DEVBUF, M_WAITOK); - if (sc->rr.bp == 0) { - free(sc, M_DEVBUF); - return (ENOMEM); - } - sc->pr.bp = malloc(AU_RING_SIZE, M_DEVBUF, M_WAITOK); - if (sc->pr.bp == 0) { - free(sc->rr.bp, M_DEVBUF); - free(sc, M_DEVBUF); - return (ENOMEM); - } + error = audio_alloc_ring(sc, &sc->sc_pr, AU_RING_SIZE); + if (error) + return error; + error = audio_alloc_ring(sc, &sc->sc_rr, AU_RING_SIZE); + if (error) { + audio_free_ring(sc, &sc->sc_pr); + return error; + } + audio_softc[n] = sc; /* @@ -304,14 +324,12 @@ audio_hardware_detach(hwp) if (sc->sc_open != 0) return(EBUSY); - sc->hw_if = 0; - /* Free audio buffers */ - free(sc->rr.bp, M_DEVBUF); - free(sc->pr.bp, M_DEVBUF); + audio_free_ring(sc, &sc->sc_rr); + audio_free_ring(sc, &sc->sc_pr); free(sc, M_DEVBUF); - audio_softc[hwp->audio_unit] = NULL; + audio_softc[hwp->audio_unit] = 0; return(0); } @@ -447,30 +465,56 @@ audiommap(dev, off, prot) * Audio driver */ void -audio_init_ring(rp, blksize) - struct audio_buffer *rp; - int blksize; +audio_init_ringbuffer(rp) + struct audio_ringbuffer *rp; { - int nblk = AU_RING_SIZE / blksize; - - rp->ep = rp->bp + nblk * blksize; - rp->hp = rp->tp = rp->bp; - rp->maxblk = nblk; - rp->nblk = 0; - rp->cb_drops = 0; - rp->cb_pdrops = 0; + int nblks; + int blksize = rp->blksize; + + nblks = rp->bufsize / blksize; + if (nblks < AUMINNOBLK) { + nblks = AUMINNOBLK; + blksize = rp->bufsize / nblks; + ROUNDSIZE(blksize); + } + DPRINTF(("audio_init_ringbuffer: blksize=%d\n", blksize)); + rp->blksize = blksize; + rp->maxblks = nblks; + rp->used = 0; + rp->end = rp->start + nblks * blksize; + rp->inp = rp->outp = rp->start; + rp->stamp = 0; + rp->drops = 0; + rp->pause = 0; + rp->copying = 0; + rp->needfill = 0; + rp->mmapped = 0; } void audio_initbufs(sc) struct audio_softc *sc; { - int nblk = AU_RING_SIZE / sc->sc_blksize; + struct audio_hw_if *hw = sc->hw_if; - audio_init_ring(&sc->rr, sc->sc_blksize); - audio_init_ring(&sc->pr, sc->sc_blksize); - sc->sc_lowat = nblk * 3 / 4; - sc->sc_hiwat = nblk; + DPRINTF(("audio_initbufs: mode=%x\n", sc->sc_mode)); + audio_init_ringbuffer(&sc->sc_rr); + if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) + hw->init_input(sc->hw_hdl, sc->sc_rr.start, + sc->sc_rr.end - sc->sc_rr.start); + + audio_init_ringbuffer(&sc->sc_pr); + sc->sc_sil_count = 0; + if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) + hw->init_output(sc->hw_hdl, sc->sc_pr.start, + sc->sc_pr.end - sc->sc_pr.start); + + sc->sc_pr.usedhigh = sc->sc_pr.end - sc->sc_pr.start; + sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; /* set lowater at 75% */ + if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh) + sc->sc_pr.usedlow -= sc->sc_pr.blksize; + sc->sc_rr.usedhigh = sc->sc_pr.end - sc->sc_pr.start - sc->sc_pr.blksize; + sc->sc_rr.usedlow = 0; } static __inline int @@ -485,11 +529,12 @@ audio_sleep_timo(chan, label, timo) label = "audio"; *chan = 1; - st = (tsleep(chan, PWAIT | PCATCH, label, timo)); + st = tsleep(chan, PWAIT | PCATCH, label, timo); *chan = 0; - if (st != 0) { - DPRINTF(("audio_sleep: %d\n", st)); - } +#ifdef AUDIO_DEBUG + if (st != 0) + printf("audio_sleep: %d\n", st); +#endif return (st); } @@ -498,7 +543,7 @@ audio_sleep(chan, label) int *chan; char *label; { - return audio_sleep_timo(chan, label, 0); + return audio_sleep_timo(chan, label, 0); } static __inline void @@ -519,7 +564,7 @@ audio_open(dev, flags, ifmt, p) { int unit = AUDIOUNIT(dev); struct audio_softc *sc; - int s, error; + int error; struct audio_hw_if *hw; if (unit >= naudio || !audio_softc[unit]) { @@ -530,19 +575,24 @@ audio_open(dev, flags, ifmt, p) sc = audio_softc[unit]; hw = sc->hw_if; - DPRINTF(("audio_open: dev=0x%x flags=0x%x sc=0x%x hdl=0x%x\n", dev, flags, sc, sc->hw_hdl)); - if (hw == 0) /* Hardware has not attached to us... */ + DPRINTF(("audio_open: dev=0x%x flags=0x%x sc=%p hdl=%p\n", dev, flags, sc, sc->hw_hdl)); +#ifdef DIAGNOSTIC + if (hw == 0) { /* Hardware has not attached to us... */ + printf("audio_open: hw==0\n"); return (ENXIO); + } +#endif - if ((sc->sc_open & (AUOPEN_READ|AUOPEN_WRITE)) != 0) /* XXX use flags */ + if ((sc->sc_open & (AUOPEN_READ|AUOPEN_WRITE)) != 0) return (EBUSY); - if ((error = hw->open(dev, flags)) != 0) + error = hw->open(dev, flags); + if (error) return (error); - if (flags&FREAD) + if (flags & FREAD) sc->sc_open |= AUOPEN_READ; - if (flags&FWRITE) + if (flags & FWRITE) sc->sc_open |= AUOPEN_WRITE; /* @@ -554,82 +604,85 @@ audio_open(dev, flags, ifmt, p) /* /dev/audio */ sc->sc_rparams = audio_default; sc->sc_pparams = audio_default; - /** XXX should we abort on error? */ - error = hw->set_params(sc->hw_hdl, AUMODE_RECORD, + if (flags & FREAD) { + error = hw->set_params(sc->hw_hdl, AUMODE_RECORD, &sc->sc_rparams, &sc->sc_pparams); - if (error) - return (error); - error = hw->set_params(sc->hw_hdl, AUMODE_PLAY, + if (error) + return (error); + } + if (flags & FWRITE) { + error = hw->set_params(sc->hw_hdl, AUMODE_PLAY, &sc->sc_pparams, &sc->sc_rparams); - if (error) - return (error); + if (error) + return (error); + } } +#ifdef DIAGNOSTIC /* * Sample rate and precision are supposed to be set to proper * default values by the hardware driver, so that it may give * us these values. */ -#ifdef DIAGNOSTIC if (sc->sc_rparams.precision == 0 || sc->sc_pparams.precision == 0) { printf("audio_open: 0 precision\n"); return EINVAL; } #endif - sc->sc_blksize = audio_calc_blksize(sc); - audio_alloc_auzero(sc, sc->sc_blksize); - sc->sc_smpl_in_blk = sc->sc_blksize / (sc->sc_pparams.precision / NBBY); - sc->sc_50ms = 50 * sc->sc_pparams.sample_rate / 1000; + if (flags & FREAD) { + audio_calc_blksize(sc, AUMODE_RECORD); + sc->sc_mode = AUMODE_RECORD; + } + if (flags & FWRITE) { + audio_calc_blksize(sc, AUMODE_PLAY); + sc->sc_mode = AUMODE_PLAY | AUMODE_PLAY_ALL; + } audio_initbufs(sc); + sc->sc_playdrop = 0; +#ifdef AUDIO_INTR_TIME + sc->sc_pnintr = 0; + sc->sc_pblktime = (u_long)( + (double)sc->sc_pr.blksize * 1e6 / + (double)(sc->sc_pparams.precision / NBBY * + sc->sc_pparams.channels * + sc->sc_pparams.sample_rate)); + DPRINTF(("audio: play blktime = %lu for %d\n", + sc->sc_pblktime, sc->sc_pr.blksize)); + sc->sc_rnintr = 0; + sc->sc_rblktime = (u_long)( + (double)sc->sc_rr.blksize * 1e6 / + (double)(sc->sc_rparams.precision / NBBY * + sc->sc_rparams.channels * + sc->sc_rparams.sample_rate)); + DPRINTF(("audio: record blktime = %lu for %d\n", + sc->sc_rblktime, sc->sc_rr.blksize)); +#endif - sc->sc_backlog = audio_backlog; - - DPRINTF(("audio_open: rr.bp=%x-%x pr.bp=%x-%x\n", - sc->rr.bp, sc->rr.ep, sc->pr.bp, sc->pr.ep)); + DPRINTF(("audio_open: rr.buf=%p-%p pr.buf=%p-%p\n", + sc->sc_rr.start, sc->sc_rr.end, sc->sc_pr.start, sc->sc_pr.end)); hw->commit_settings(sc->hw_hdl); - s = splaudio(); - - /* nothing read or written yet */ - sc->sc_rseek = 0; - sc->sc_wseek = 0; - sc->sc_rchan = 0; sc->sc_wchan = 0; sc->sc_rbus = 0; sc->sc_pbus = 0; - if ((flags & FWRITE) != 0) { + sc->sc_eof = 0; + + if ((flags & (FWRITE|FREAD)) == (FWRITE|FREAD)) + sc->sc_full_duplex = (hw->props & AUDIO_PROP_FULLDUPLEX) != 0; + + if (flags & FWRITE) audio_init_play(sc); - /* audio_pint(sc); ??? */ - } - if ((flags & FREAD) != 0) { + if (flags & FREAD) { /* Play takes precedence if HW is half-duplex */ - if (hw->full_duplex || ((flags & FWRITE) == 0)) { + if (sc->sc_full_duplex || (flags & FWRITE) == 0) audio_init_record(sc); - /* audiostartr(sc); don't start recording until read */ - } - } - if (ISDEVAUDIO(dev)) { - /* if open only for read or only for write, then set specific mode */ - if ((flags & (FWRITE|FREAD)) == FWRITE) { - sc->sc_mode = AUMODE_PLAY; - sc->pr.cb_pause = 0; - sc->rr.cb_pause = 1; - audiostartp(sc); - } else if ((flags & (FWRITE|FREAD)) == FREAD) { - sc->sc_mode = AUMODE_RECORD; - sc->rr.cb_pause = 0; - sc->pr.cb_pause = 1; - audiostartr(sc); - } } - /* Play all sample, and don't pad short writes by default */ - sc->sc_mode |= AUMODE_PLAY_ALL; - splx(s); + return (0); } @@ -644,7 +697,7 @@ audio_init_record(sc) sc->sc_mode |= AUMODE_RECORD; if (sc->hw_if->speaker_ctl && - (!sc->hw_if->full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0)) + (!sc->sc_full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0)) sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_OFF); splx(s); } @@ -658,8 +711,9 @@ audio_init_play(sc) { int s = splaudio(); + sc->sc_wstamp = sc->sc_pr.stamp; + sc->sc_mode |= AUMODE_PLAY; - sc->sc_rblks = sc->sc_wblks = 0; if (sc->hw_if->speaker_ctl) sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_ON); splx(s); @@ -669,17 +723,43 @@ int audio_drain(sc) struct audio_softc *sc; { - int error; - - while (sc->pr.nblk > 0) { - DPRINTF(("audio_drain: nblk=%d\n", sc->pr.nblk)); + int error, drops; + struct audio_ringbuffer *cb = &sc->sc_pr; + + if (sc->sc_pr.mmapped || sc->sc_pr.used <= 0) + return 0; + if (!sc->sc_pbus) { + /* We've never started playing, probably because the + * block was too short. Pad it and start now. + */ + int s, cc; + u_char *inp = cb->inp; + + cc = cb->blksize - (inp - cb->start) % cb->blksize; + audio_fill_silence(&sc->sc_pparams, inp, cc); + inp += cc; + if (inp >= cb->end) + inp = cb->start; + s = splaudio(); + cb->used += cc; + cb->inp = inp; + audiostartp(sc); + splx(s); + } + /* + * Play until a silence block has been played, then we + * know all has been drained. + * XXX This should be done some other way to avoid + * playing silence. + */ + drops = cb->drops; + while (cb->drops == drops) { + DPRINTF(("audio_drain: used=%d\n", sc->sc_pr.used)); /* - * XXX * When the process is exiting, it ignores all signals and - * we can't interrupt this sleep, so we set a 1-minute - * timeout. + * we can't interrupt this sleep, so we set a timeout just in case. */ - error = audio_sleep_timo(&sc->sc_wchan, "aud dr", 60*hz); + error = audio_sleep_timo(&sc->sc_wchan, "aud dr", 30*hz); if (error) return (error); } @@ -706,22 +786,22 @@ audio_close(dev, flags, ifmt, p) /* * Block until output drains, but allow ^C interrupt. */ - sc->sc_lowat = 0; /* avoid excessive wakeups */ + sc->sc_pr.usedlow = sc->sc_pr.blksize; /* avoid excessive wakeups */ s = splaudio(); /* * If there is pending output, let it drain (unless * the output is paused). */ - if (sc->sc_pbus && sc->pr.nblk > 0 && !sc->pr.cb_pause) { + if (!sc->sc_pr.pause) { if (!audio_drain(sc) && hw->drain) (void)hw->drain(sc->hw_hdl); } hw->close(sc->hw_hdl); - if (flags&FREAD) + if (flags & FREAD) sc->sc_open &= ~AUOPEN_READ; - if (flags&FWRITE) + if (flags & FWRITE) sc->sc_open &= ~AUOPEN_WRITE; sc->sc_async = 0; @@ -739,34 +819,30 @@ audio_read(dev, uio, ioflag) { int unit = AUDIOUNIT(dev); struct audio_softc *sc = audio_softc[unit]; - struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->rr; - u_char *hp; - int blocksize = sc->sc_blksize; - int error, s; - - DPRINTF(("audio_read: cc=%d mode=%d rblks=%d\n", - uio->uio_resid, sc->sc_mode, sc->sc_rblks)); - - if (uio->uio_resid == 0) - return (0); + struct audio_ringbuffer *cb = &sc->sc_rr; + u_char *outp; + int error, s, used, cc, n; - if (uio->uio_resid < blocksize) - return (EINVAL); + if (cb->mmapped) + return EINVAL; - /* First sample we'll read in sample space */ - sc->sc_rseek = cb->au_stamp - AU_RING_LEN(cb); + DPRINTF(("audio_read: cc=%d mode=%d\n", uio->uio_resid, sc->sc_mode)); + error = 0; /* * If hardware is half-duplex and currently playing, return * silence blocks based on the number of blocks we have output. */ - if ((!hw->full_duplex) && + if (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_PLAY)) { - do { + while (uio->uio_resid > 0 && !error) { s = splaudio(); - while (sc->sc_rblks <= 0) { - DPRINTF(("audio_read: sc_rblks=%d\n", sc->sc_rblks)); + for(;;) { + cc = sc->sc_pr.stamp - sc->sc_wstamp; + if (cc > 0) + break; + DPRINTF(("audio_read: stamp=%lu, wstamp=%lu\n", + sc->sc_pr.stamp, sc->sc_wstamp)); if (ioflag & IO_NDELAY) { splx(s); return (EWOULDBLOCK); @@ -778,18 +854,20 @@ audio_read(dev, uio, ioflag) } } splx(s); - error = audio_silence_copyout(sc, blocksize, uio); - if (error) - break; - s = splaudio(); - --sc->sc_rblks; - splx(s); - } while (uio->uio_resid >= blocksize); + + if (uio->uio_resid < cc) + cc = uio->uio_resid; +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_read: reading in write mode, cc=%d\n", cc); +#endif + error = audio_silence_copyout(sc, cc, uio); + sc->sc_wstamp += cc; + } return (error); } - error = 0; - do { - while (cb->nblk <= 0) { + while (uio->uio_resid > 0 && !error) { + while (cb->used <= 0) { if (ioflag & IO_NDELAY) { error = EWOULDBLOCK; return (error); @@ -797,24 +875,45 @@ audio_read(dev, uio, ioflag) s = splaudio(); if (!sc->sc_rbus) audiostartr(sc); +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_read: sleep used=%d\n", cb->used); +#endif error = audio_sleep(&sc->sc_rchan, "aud rd"); splx(s); if (error) return (error); } - hp = cb->hp; - if (sc->sc_rparams.sw_code) - sc->sc_rparams.sw_code(sc->hw_hdl, hp, blocksize); - error = uiomove(hp, blocksize, uio); - if (error) - break; - hp += blocksize; - if (hp >= cb->ep) - hp = cb->bp; - cb->hp = hp; - --cb->nblk; - } while (uio->uio_resid >= blocksize); + s = splaudio(); + used = cb->used; + outp = cb->outp; + cb->copying = 1; + splx(s); + cc = used - cb->usedlow; /* maximum to read */ + n = cb->end - outp; + if (n < cc) + cc = n; /* don't read beyond end of buffer */ + + if (uio->uio_resid < cc) + cc = uio->uio_resid; /* and no more than we want */ + if (sc->sc_rparams.sw_code) + sc->sc_rparams.sw_code(sc->hw_hdl, outp, cc); +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_read: outp=%p, cc=%d\n", outp, cc); +#endif + error = uiomove(outp, cc, uio); + used -= cc; + outp += cc; + if (outp >= cb->end) + outp = cb->start; + s = splaudio(); + cb->outp = outp; + cb->used = used; + cb->copying = 0; + splx(s); + } return (error); } @@ -830,32 +929,37 @@ audio_clear(sc) sc->sc_rbus = 0; sc->sc_pbus = 0; } - AU_RING_INIT(&sc->rr); - AU_RING_INIT(&sc->pr); - sc->sc_rblks = sc->sc_wblks = 0; + audio_init_ringbuffer(&sc->sc_rr); + audio_init_ringbuffer(&sc->sc_pr); splx(s); } -int -audio_calc_blksize(sc) +void +audio_calc_blksize(sc, mode) struct audio_softc *sc; + int mode; { struct audio_hw_if *hw = sc->hw_if; + struct audio_params *parm; + struct audio_ringbuffer *rb; int bs; + + if (mode == AUMODE_PLAY) { + parm = &sc->sc_pparams; + rb = &sc->sc_pr; + } else { + parm = &sc->sc_rparams; + rb = &sc->sc_rr; + } - bs = sc->sc_pparams.sample_rate * audio_blk_ms / 1000; - if (bs == 0) - bs = 1; - bs *= sc->sc_pparams.channels; - bs *= sc->sc_pparams.precision / NBBY; - if (bs > AU_RING_SIZE/2) - bs = AU_RING_SIZE/2; - bs = hw->round_blocksize(sc->hw_hdl, bs); - if (bs > AU_RING_SIZE) - bs = AU_RING_SIZE; - - return(bs); + bs = parm->sample_rate * audio_blk_ms / 1000 * + parm->channels * parm->precision / NBBY; + ROUNDSIZE(bs); + rb->blksize = hw->round_blocksize(sc->hw_hdl, bs); + + DPRINTF(("audio_calc_blksize: %s blksize=%d\n", + mode == AUMODE_PLAY ? "play" : "record", bs)); } void @@ -864,47 +968,47 @@ audio_fill_silence(params, p, n) u_char *p; int n; { - u_char auzero[2]; + u_char auzero0, auzero1 = 0; /* initialize to please gcc */ int nfill = 1; - + switch (params->encoding) { case AUDIO_ENCODING_ULAW: - auzero[0] = 0x7f; + auzero0 = 0x7f; break; case AUDIO_ENCODING_ALAW: - auzero[0] = 0x55; + auzero0 = 0x55; break; case AUDIO_ENCODING_ADPCM: /* is this right XXX */ case AUDIO_ENCODING_SLINEAR_LE: case AUDIO_ENCODING_SLINEAR_BE: - auzero[0] = 0; /* fortunately this works for both 8 and 16 bits */ + auzero0 = 0; /* fortunately this works for both 8 and 16 bits */ break; case AUDIO_ENCODING_ULINEAR_LE: case AUDIO_ENCODING_ULINEAR_BE: if (params->precision == 16) { nfill = 2; if (params->encoding == AUDIO_ENCODING_ULINEAR_LE) { - auzero[0] = 0; - auzero[1] = 0x80; + auzero0 = 0; + auzero1 = 0x80; } else { - auzero[0] = 0x80; - auzero[1] = 0; + auzero0 = 0x80; + auzero1 = 0; } } else - auzero[0] = 0x80; + auzero0 = 0x80; break; default: printf("audio: bad encoding %d\n", params->encoding); - auzero[0] = 0; + auzero0 = 0; break; } if (nfill == 1) { while (--n >= 0) - *p++ = auzero[0]; /* XXX memset */ - } else /* must be 2 */ { + *p++ = auzero0; /* XXX memset */ + } else /* nfill must be 2 */ { while (n > 1) { - *p++ = auzero[0]; - *p++ = auzero[1]; + *p++ = auzero0; + *p++ = auzero1; n -= 2; } } @@ -931,26 +1035,6 @@ audio_silence_copyout(sc, n, uio) return (error); } -void -audio_alloc_auzero(sc, bs) - struct audio_softc *sc; - int bs; -{ - if (sc->auzero_block) - free(sc->auzero_block, M_DEVBUF); - - sc->auzero_block = malloc(bs, M_DEVBUF, M_WAITOK); -#ifdef DIAGNOSTIC - if (sc->auzero_block == 0) { - panic("audio_alloc_auzero: malloc auzero_block failed"); - } -#endif - audio_fill_silence(&sc->sc_pparams, sc->auzero_block, bs); - if (sc->sc_pparams.sw_code) - sc->sc_pparams.sw_code(sc->hw_hdl, sc->auzero_block, bs); -} - - int audio_write(dev, uio, ioflag) dev_t dev; @@ -959,168 +1043,118 @@ audio_write(dev, uio, ioflag) { int unit = AUDIOUNIT(dev); struct audio_softc *sc = audio_softc[unit]; - struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->pr; - u_char *tp; - int error, s, cc; - int blocksize = sc->sc_blksize; + struct audio_ringbuffer *cb = &sc->sc_pr; + u_char *inp, *einp; + int error, s, n, cc, used; + + DPRINTF(("audio_write: count=%d used=%d(hi=%d)\n", uio->uio_resid, + sc->sc_pr.used, sc->sc_pr.usedhigh)); + + if (cb->mmapped) + return EINVAL; + + if (uio->uio_resid == 0) { + sc->sc_eof++; + return 0; + } - DPRINTF(("audio_write: cc=%d hiwat=%d\n", uio->uio_resid, sc->sc_hiwat)); /* * If half-duplex and currently recording, throw away data. */ - if (!hw->full_duplex && + if (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_RECORD)) { uio->uio_offset += uio->uio_resid; uio->uio_resid = 0; DPRINTF(("audio_write: half-dpx read busy\n")); return (0); } - error = 0; - while (uio->uio_resid > 0) { - if (cb->fill > 0) { - if (sc->sc_pbus == 0) { - /* playing has stopped, ignore fill */ - cb->fill = 0; - } else { - /* Write samples in the silence fill space. - * We don't know where the DMA is - * happening in the buffer, but if we - * are lucky we will fill the buffer before - * playing has reached the point we move to. - * If we are unlucky some sample will - * not be played. - */ - cc = min(cb->fill, uio->uio_resid); - error = uiomove(cb->otp, cc, uio); - if (error == 0) { - if (sc->sc_pparams.sw_code) - sc->sc_pparams.sw_code(sc->hw_hdl, - cb->otp, cc); - cb->fill -= cc; - cb->otp += cc; - } - continue; - } - } - if (cb->nblk >= sc->sc_hiwat) { - do { - DPRINTF(("audio_write: nblk=%d hiwat=%d lowat=%d\n", cb->nblk, sc->sc_hiwat, sc->sc_lowat)); - if (ioflag & IO_NDELAY) - return (EWOULDBLOCK); - error = audio_sleep(&sc->sc_wchan, "aud wr"); - if (error) - return (error); - } while (cb->nblk >= sc->sc_lowat); - } -#if 0 - if (cb->nblk == 0 && - cb->maxblk > sc->sc_backlog && - uio->uio_resid <= blocksize && - (cb->au_stamp - sc->sc_wseek) > sc->sc_50ms) { - /* - * the write is 'small', the buffer is empty - * and we have been silent for at least 50ms - * so we might be dealing with an application - * that writes frames synchronously with - * reading them. If so, we need an output - * backlog to cover scheduling delays or - * there will be gaps in the sound output. - * Also take this opportunity to reset the - * buffer pointers in case we ended up on - * a bad boundary (odd byte, blksize bytes - * from end, etc.). - */ - DPRINTF(("audiowrite: set backlog %d\n", sc->sc_backlog)); - s = splaudio(); - cb->hp = cb->bp; - cb->nblk = sc->sc_backlog; - cb->tp = cb->hp + sc->sc_backlog * blocksize; - splx(s); - audio_fill_silence(&sc->sc_pparams, cb->hp, sc->sc_backlog * blocksize); + if (!(sc->sc_mode & AUMODE_PLAY_ALL) && sc->sc_playdrop > 0) { + n = min(sc->sc_playdrop, uio->uio_resid); + uio->uio_offset += n; + uio->uio_resid -= n; + sc->sc_playdrop -= n; + if (uio->uio_resid == 0) + return 0; + } + + error = 0; + while (uio->uio_resid > 0 && !error) { + while (cb->used >= cb->usedhigh) { + DPRINTF(("audio_write: sleep used=%d lowat=%d hiwat=%d\n", + cb->used, cb->usedlow, cb->usedhigh)); + if (ioflag & IO_NDELAY) + return (EWOULDBLOCK); + error = audio_sleep(&sc->sc_wchan, "aud wr"); + if (error) + return (error); } -#endif - /* Calculate sample number of first sample in block we write */ s = splaudio(); - sc->sc_wseek = AU_RING_LEN(cb) + cb->au_stamp; + used = cb->used; + inp = cb->inp; + cb->copying = 1; splx(s); - - tp = cb->tp; - cc = uio->uio_resid; + cc = cb->usedhigh - used; /* maximum to write */ + n = cb->end - inp; + if (n < cc) + cc = n; /* don't write beyond end of buffer */ + if (uio->uio_resid < cc) + cc = uio->uio_resid; /* and no more than we have */ #ifdef AUDIO_DEBUG - if (audiodebug > 1) { - int left = cb->ep - tp; - Dprintf("audio_write: cc=%d tp=%p bs=%d nblk=%d left=%d\n", cc, tp, blocksize, cb->nblk, left); - } -#endif -#ifdef DIAGNOSTIC - { - int towrite = (cc < blocksize)?cc:blocksize; - - /* check for an overwrite. Should never happen */ - if ((tp + towrite) > cb->ep) { - DPRINTF(("audio_write: overwrite tp=%p towrite=%d ep=0x%x bs=%d\n", - tp, towrite, cb->ep, blocksize)); - printf("audio_write: overwrite tp=%p towrite=%d ep=%p\n", - tp, towrite, cb->ep); - tp = cb->bp; - } - } + if (audiodebug > 1) + printf("audio_write: uiomove cc=%d inp=%p, left=%d\n", cc, inp, uio->uio_resid); #endif - if (cc < blocksize) { - error = uiomove(tp, cc, uio); - if (error == 0) { - /* fill with audio silence */ - tp += cc; - cc = blocksize - cc; - cb->fill = cc; - cb->otp = tp; - audio_fill_silence(&sc->sc_pparams, tp, cc); - DPRINTF(("audio_write: auzero 0x%x %d 0x%x\n", - tp, cc, *tp)); - tp += cc; - } - } else { - error = uiomove(tp, blocksize, uio); - if (error == 0) { - tp += blocksize; - } - } - if (error) { + n = uio->uio_resid; + error = uiomove(inp, cc, uio); + cc = n - uio->uio_resid; /* number of bytes actually moved */ #ifdef AUDIO_DEBUG - printf("audio_write:(1) uiomove failed %d; cc=%d tp=%p bs=%d\n", error, cc, tp, blocksize); + if (error) + printf("audio_write:(1) uiomove failed %d; cc=%d inp=%p\n", + error, cc, inp); #endif - break; - } - + /* Continue even if uiomove() failed because we may have + * gotten a partial block. */ if (sc->sc_pparams.sw_code) - sc->sc_pparams.sw_code(sc->hw_hdl, cb->tp, blocksize); + sc->sc_pparams.sw_code(sc->hw_hdl, inp, cc); + + einp = cb->inp + cc; + if (einp >= cb->end) + einp = cb->start; - /* wrap the ring buffer if at end */ s = splaudio(); - if ((sc->sc_mode & AUMODE_PLAY_ALL) == 0 && sc->sc_wblks) - /* - * discard the block if we sent out a silence - * packet that hasn't yet been countered - * by user data. (They must supply enough - * data to catch up to "real time"). - */ - sc->sc_wblks--; - else { - if (tp >= cb->ep) - tp = cb->bp; - cb->tp = tp; - ++cb->nblk; /* account for buffer filled */ - - /* - * If output isn't active, start it up. - */ - if (sc->sc_pbus == 0) - audiostartp(sc); - } + /* + * This is a very suboptimal way of keeping track of + * silence in the buffer, but it is simple. + */ + sc->sc_sil_count = 0; + + cb->inp = einp; + cb->used += cc; + /* If the interrupt routine wants the last block filled AND + * the copy did not fill the last block completely it needs to + * be padded. + */ + if (cb->needfill && + (inp - cb->start) / cb->blksize == + (einp - cb->start) / cb->blksize) { + /* Figure out how many bytes there is to a block boundary. */ + cc = cb->blksize - (einp - cb->start) % cb->blksize; + DPRINTF(("audio_write: partial fill %d\n", cc)); + } else + cc = 0; + cb->needfill = 0; + cb->copying = 0; + if (!sc->sc_pbus && !cb->pause) + audiostartp(sc); splx(s); + if (cc) { +#ifdef AUDIO_DEBUG + if (audiodebug > 1) + printf("audio_write: fill %d\n", cc); +#endif + audio_fill_silence(&sc->sc_pparams, einp, cc); + } } return (error); } @@ -1136,12 +1170,12 @@ audio_ioctl(dev, cmd, addr, flag, p) int unit = AUDIOUNIT(dev); struct audio_softc *sc = audio_softc[unit]; struct audio_hw_if *hw = sc->hw_if; - int error = 0, s; + struct audio_offset *ao; + int error = 0, s, offs; DPRINTF(("audio_ioctl(%d,'%c',%d)\n", IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff)); switch (cmd) { - case FIOASYNC: if (*(int *)addr) { if (sc->sc_async) @@ -1151,18 +1185,15 @@ audio_ioctl(dev, cmd, addr, flag, p) sc->sc_async = 0; break; - case FIONBIO: /* to be removed? */ - break; - case AUDIO_FLUSH: DPRINTF(("AUDIO_FLUSH\n")); audio_clear(sc); s = splaudio(); - if ((sc->sc_mode & AUMODE_PLAY) && (sc->sc_pbus == 0)) + if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_pbus) audiostartp(sc); /* Again, play takes precedence on half-duplex hardware */ if ((sc->sc_mode & AUMODE_RECORD) && - (hw->full_duplex || + (sc->sc_full_duplex || ((sc->sc_mode & AUMODE_PLAY) == 0))) audiostartr(sc); splx(s); @@ -1173,25 +1204,51 @@ audio_ioctl(dev, cmd, addr, flag, p) * when they were dropped. */ case AUDIO_RERROR: - *(int *)addr = sc->rr.cb_drops; + *(int *)addr = sc->sc_rr.drops; break; case AUDIO_PERROR: - *(int *)addr = sc->pr.cb_drops; + *(int *)addr = sc->sc_pr.drops; break; /* - * How many samples will elapse until mike hears the first - * sample of what we last wrote? + * Offsets into buffer. */ - case AUDIO_WSEEK: + case AUDIO_GETIOFFS: + s = splaudio(); + /* figure out where next DMA will start */ + ao = (struct audio_offset *)addr; + ao->samples = sc->sc_rr.stamp; + ao->deltablks = (sc->sc_rr.stamp - sc->sc_rr.stamp_last) / sc->sc_rr.blksize; + sc->sc_rr.stamp_last = sc->sc_rr.stamp; + ao->offset = sc->sc_rr.inp - sc->sc_rr.start; + splx(s); + break; + + case AUDIO_GETOOFFS: s = splaudio(); - *(u_long *)addr = sc->sc_wseek - sc->pr.au_stamp - + AU_RING_LEN(&sc->rr); + /* figure out where next DMA will start */ + ao = (struct audio_offset *)addr; + offs = sc->sc_pr.outp - sc->sc_pr.start + sc->sc_pr.blksize; + if (sc->sc_pr.start + offs >= sc->sc_pr.end) + offs = 0; + ao->samples = sc->sc_pr.stamp; + ao->deltablks = (sc->sc_pr.stamp - sc->sc_pr.stamp_last) / sc->sc_pr.blksize; + sc->sc_pr.stamp_last = sc->sc_pr.stamp; + ao->offset = offs; splx(s); break; + + /* + * How many bytes will elapse until mike hears the first + * sample of what we write next? + */ + case AUDIO_WSEEK: + *(u_long *)addr = sc->sc_rr.used; + break; + case AUDIO_SETINFO: - DPRINTF(("AUDIO_SETINFO\n")); + DPRINTF(("AUDIO_SETINFO mode=%x\n", sc->sc_mode)); error = audiosetinfo(sc, (struct audio_info *)addr); break; @@ -1219,12 +1276,19 @@ audio_ioctl(dev, cmd, addr, flag, p) case AUDIO_GETFD: DPRINTF(("AUDIO_GETFD\n")); - *(int *)addr = hw->full_duplex; + *(int *)addr = sc->sc_full_duplex; break; case AUDIO_SETFD: DPRINTF(("AUDIO_SETFD\n")); error = hw->setfd(sc->hw_hdl, *(int *)addr); + if (error == 0) + sc->sc_full_duplex = *(int *)addr; + break; + + case AUDIO_GETPROPS: + DPRINTF(("AUDIO_GETPROPS\n")); + *(int *)addr = hw->props; break; default: @@ -1249,18 +1313,18 @@ audio_poll(dev, events, p) int s = splaudio(); #if 0 - DPRINTF(("audio_poll: events=%d mode=%d rblks=%d rr.nblk=%d\n", - events, sc->sc_mode, sc->sc_rblks, sc->rr.nblk)); + DPRINTF(("audio_poll: events=%d mode=%d rr.nblk=%d\n", + events, sc->sc_mode, sc->sc_rr.nblk)); #endif if (events & (POLLIN | POLLRDNORM)) if ((sc->sc_mode & AUMODE_PLAY) ? - (sc->sc_rblks > 0) : (sc->rr.nblk > 0)) + 0/*XXX*/ : sc->sc_rr.used > sc->sc_rr.usedlow) revents |= events & (POLLIN | POLLRDNORM); if (events & (POLLOUT | POLLWRNORM)) - if ((sc->sc_mode & AUMODE_RECORD) ? - 1 : (sc->pr.nblk <= sc->sc_lowat)) + if (sc->sc_mode & AUMODE_RECORD || + sc->sc_pr.used < sc->sc_pr.usedlow) revents |= events & (POLLOUT | POLLWRNORM); if (revents == 0) { @@ -1280,9 +1344,59 @@ audio_mmap(dev, off, prot) dev_t dev; int off, prot; { + int s; + int unit = AUDIOUNIT(dev); + struct audio_softc *sc = audio_softc[unit]; + struct audio_hw_if *hw = sc->hw_if; + struct audio_ringbuffer *cb; + + DPRINTF(("audio_mmap: off=%d, prot=%d\n", off, prot)); + + if (!(hw->props & AUDIO_PROP_MMAP)) + return -1; +#if 0 +/* XXX + * The idea here was to use the protection to determine if + * we are mapping the read or write buffer, but it fails. + * The VM system is broken in (at least) two ways. + * 1) If you map memory VM_PROT_WRITE you SIGSEGV + * when writing to it, so VM_PROT_READ|VM_PROT_WRITE + * has to be used for mmapping the play buffer. + * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE + * audio_mmap will get called at some point with VM_PROT_READ + * only. + * So, alas, we always map the play buffer for now. + */ + if (prot == (VM_PROT_READ|VM_PROT_WRITE) || + prot == VM_PROT_WRITE) + cb = &sc->sc_pr; + else if (prot == VM_PROT_READ) + cb = &sc->sc_rr; + else + return -1; +#else + cb = &sc->sc_pr; +#endif - /* XXX placeholder */ - return (-1); + if (off >= cb->bufsize) + return -1; + if (!cb->mmapped) { + cb->mmapped = 1; + if (cb == &sc->sc_pr) { + audio_fill_silence(&sc->sc_pparams, cb->start, cb->bufsize); + s = splaudio(); + if (!sc->sc_pbus) + audiostartp(sc); + splx(s); + } else { + s = splaudio(); + if (!sc->sc_rbus) + audiostartr(sc); + splx(s); + } + } + + return i386_btop(vtophys((caddr_t)cb->start + off)); } void @@ -1291,15 +1405,16 @@ audiostartr(sc) { int error; - DPRINTF(("audiostartr: tp=%p\n", sc->rr.tp)); + DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n", + sc->sc_rr.start, sc->sc_rr.used, sc->sc_rr.usedhigh, + sc->sc_rr.mmapped)); - error = sc->hw_if->start_input(sc->hw_hdl, sc->rr.tp, sc->sc_blksize, - audio_rint, (void *)sc); + error = sc->hw_if->start_input(sc->hw_hdl, sc->sc_rr.start, + sc->sc_rr.blksize, audio_rint, (void *)sc); if (error) { DPRINTF(("audiostartr failed: %d\n", error)); audio_clear(sc); - } - else + } else sc->sc_rbus = 1; } @@ -1309,36 +1424,77 @@ audiostartp(sc) { int error; - DPRINTF(("audiostartp: hp=0x%x nblk=%d\n", sc->pr.hp, sc->pr.nblk)); + DPRINTF(("audiostartp: start=%p used=%d(hi=%d) mmapped=%d\n", + sc->sc_pr.start, sc->sc_pr.used, sc->sc_pr.usedhigh, + sc->sc_pr.mmapped)); - if (sc->pr.nblk > 0) { - u_char *hp = sc->pr.hp; - error = sc->hw_if->start_output(sc->hw_hdl, hp, sc->sc_blksize, - audio_rpint, (void *)sc); + if (sc->sc_pr.used >= sc->sc_pr.blksize || sc->sc_pr.mmapped) { + error = sc->hw_if->start_output(sc->hw_hdl, sc->sc_pr.outp, + sc->sc_pr.blksize, audio_pint, (void *)sc); if (error) { DPRINTF(("audiostartp: failed: %d\n", error)); - } - else { + } else { sc->sc_pbus = 1; - hp += sc->sc_blksize; - if (hp >= sc->pr.ep) - hp = sc->pr.bp; - sc->pr.hp = hp; } } } /* - * Use this routine as DMA callback if we played user data. We need to - * account for user data and silence separately. + * When the play interrupt routine finds that the write isn't keeping + * the buffer filled it will insert silence in the buffer to make up + * for this. The part of the buffer that is filled with silence + * is kept track of in a very approcimate way: it starts at sc_sil_start + * and extends sc_sil_count bytes. If the writer doesn't write sc_sil_count + * get to encompass the whole buffer after which no more filling needs + * to be done. When the writer starts again sc_sil_count is set to 0. */ -void -audio_rpint(v) - void *v; +/* XXX + * Putting silence into the output buffer should not really be done + * at splaudio, but there is no softaudio level to do it at yet. + */ +static __inline void +audio_pint_silence(sc, cb, inp, cc) + struct audio_softc *sc; + struct audio_ringbuffer *cb; + u_char *inp; + int cc; { - struct audio_softc *sc = v; - sc->pr.nblk--; - audio_pint(v); /* 'twas a real audio block */ + u_char *s, *e, *p, *q; + + if (sc->sc_sil_count > 0) { + s = sc->sc_sil_start; /* start of silence */ + e = s + sc->sc_sil_count; /* end of silence, may be beyond end */ + p = inp; /* adjusted pointer to area to fill */ + if (p < s) + p += cb->end - cb->start; + q = p+cc; + /* Check if there is already silence. */ + if (!(s <= p && p < e && + s <= q && q <= e)) { + if (s <= p) + sc->sc_sil_count = max(sc->sc_sil_count, q - s); +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_pint_silence: fill cc=%d inp=%p, count=%d size=%d\n", + cc, inp, sc->sc_sil_count, (int)(cb->end - cb->start)); +#endif + audio_fill_silence(&sc->sc_pparams, inp, cc); + } else { +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_pint_silence: already silent cc=%d inp=%p\n", cc, inp); +#endif + + } + } else { + sc->sc_sil_start = inp; + sc->sc_sil_count = cc; +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_pint_silence: start fill %p %d\n", inp, cc); +#endif + audio_fill_silence(&sc->sc_pparams, inp, cc); + } } /* @@ -1352,74 +1508,105 @@ audio_pint(v) void *v; { struct audio_softc *sc = v; - u_char *hp; - int cc = sc->sc_blksize; struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->pr; + struct audio_ringbuffer *cb = &sc->sc_pr; + u_char *inp; + int cc, n; int error; - - /* - * XXX - * if there is only one buffer in the ring, this test - * always fails and the output is always silence after the - * first block. - */ - if (cb->nblk > 0) { - hp = cb->hp; - if (cb->cb_pause) { - cb->cb_pdrops++; + + n = (cb->outp - cb->start) / cb->blksize; + cb->outp += cb->blksize; + if (cb->outp >= cb->end) + cb->outp = cb->start; + cb->stamp += cb->blksize; + if (cb->mmapped) { #ifdef AUDIO_DEBUG - if (audiodebug > 2) - Dprintf("audio_pint: paused %d\n", cb->cb_pdrops); + if (audiodebug > 2) + printf("audio_pint: mmapped outp=%p cc=%d inp=%p\n", + cb->outp, cb->blksize, cb->inp); #endif - goto psilence; - } - else { + hw->start_output(sc->hw_hdl, cb->outp, cb->blksize, + audio_pint, (void *)sc); + return; + } + +#ifdef AUDIO_INTR_TIME + { + struct timeval tv; + u_long t; + microtime(&tv); + t = tv.tv_usec + 1000000 * tv.tv_sec; + if (sc->sc_pnintr) { + long lastdelta, totdelta; + lastdelta = t - sc->sc_plastintr - sc->sc_pblktime; + if (lastdelta > sc->sc_pblktime / 5) { + printf("audio: play interrupt(%d) off relative by %ld us (%lu)\n", + sc->sc_pnintr, lastdelta, sc->sc_pblktime); + } + totdelta = t - sc->sc_pfirstintr - sc->sc_pblktime * sc->sc_pnintr; + if (totdelta > sc->sc_pblktime / 2) { + sc->sc_pnintr++; + printf("audio: play interrupt(%d) off absolute by %ld us (%lu)\n", + sc->sc_pnintr, totdelta, sc->sc_pblktime); + sc->sc_pnintr++; /* avoid repeated messages */ + } + } else + sc->sc_pfirstintr = t; + sc->sc_plastintr = t; + sc->sc_pnintr++; + } +#endif + + cb->used -= cb->blksize; + if (cb->used < cb->blksize) { + /* we don't have a full block to use */ + if (cb->copying) { + /* writer is in progress, don't disturb */ + cb->needfill = 1; #ifdef AUDIO_DEBUG - if (audiodebug > 2) - Dprintf("audio_pint: hp=0x%x cc=%d\n", hp, cc); + if (audiodebug > 1) + printf("audio_pint: copying in progress\n"); #endif - error = hw->start_output(sc->hw_hdl, hp, cc, - audio_rpint, (void *)sc); - if (error) { - DPRINTF(("audio_pint restart failed: %d\n", error)); - audio_clear(sc); - } - else { - hp += cc; - if (hp >= cb->ep) - hp = cb->bp; - cb->hp = hp; - cb->au_stamp += sc->sc_smpl_in_blk; - - ++sc->sc_rblks; - } + } else { + inp = cb->inp; + cc = cb->blksize - (inp - cb->start) % cb->blksize; + if (cb->pause) + cb->pdrops += cc; + else { + cb->drops += cc; + sc->sc_playdrop += cc; + } + audio_pint_silence(sc, cb, inp, cc); + inp += cc; + if (inp >= cb->end) + inp = cb->start; + cb->inp = inp; + cb->used += cc; + + /* Clear next block so we keep ahead of the DMA. */ + if (cb->used + cc < cb->usedhigh) + audio_pint_silence(sc, cb, inp, cb->blksize); } } - else { - cb->cb_drops++; + #ifdef AUDIO_DEBUG - if (audiodebug > 2) - Dprintf("audio_pint: drops=%d auzero %d 0x%x\n", cb->cb_drops, cc, *(int *)sc->auzero_block); + if (audiodebug > 3) + printf("audio_pint: outp=%p cc=%d\n", cb->outp, cb->blksize); #endif - psilence: - error = hw->start_output(sc->hw_hdl, - sc->auzero_block, cc, - audio_pint, (void *)sc); - if (error) { - DPRINTF(("audio_pint zero failed: %d\n", error)); - audio_clear(sc); - } else - ++sc->sc_wblks; + error = hw->start_output(sc->hw_hdl, cb->outp, cb->blksize, + audio_pint, (void *)sc); + if (error) { + DPRINTF(("audio_pint restart failed: %d\n", error)); + audio_clear(sc); } #ifdef AUDIO_DEBUG - if (audiodebug > 1) - Dprintf("audio_pint: mode=%d pause=%d nblk=%d lowat=%d\n", - sc->sc_mode, cb->cb_pause, cb->nblk, sc->sc_lowat); + if (audiodebug > 3) + printf("audio_pint: mode=%d pause=%d used=%d lowat=%d\n", + sc->sc_mode, cb->pause, cb->used, cb->usedlow); #endif - if ((sc->sc_mode & AUMODE_PLAY) && !cb->cb_pause) { - if (cb->nblk <= sc->sc_lowat) { + if ((sc->sc_mode & AUMODE_PLAY) && !cb->pause) { + if (cb->used <= cb->usedlow) { audio_wakeup(&sc->sc_wchan); selwakeup(&sc->sc_wsel); if (sc->sc_async) @@ -1427,12 +1614,8 @@ audio_pint(v) } } - /* - * XXX - * possible to return one or more "phantom blocks" now. - * Only in half duplex? - */ - if (hw->full_duplex) { + /* Possible to return one or more "phantom blocks" now. */ + if (!sc->sc_full_duplex && sc->sc_rchan) { audio_wakeup(&sc->sc_rchan); selwakeup(&sc->sc_rsel); if (sc->sc_async) @@ -1450,53 +1633,81 @@ audio_rint(v) void *v; { struct audio_softc *sc = v; - u_char *tp; - int cc = sc->sc_blksize; struct audio_hw_if *hw = sc->hw_if; - struct audio_buffer *cb = &sc->rr; + struct audio_ringbuffer *cb = &sc->sc_rr; int error; - - tp = cb->tp; - if (cb->cb_pause) { - cb->cb_pdrops++; - DPRINTF(("audio_rint: pdrops %d\n", cb->cb_pdrops)); - } - else { - tp += cc; - if (tp >= cb->ep) - tp = cb->bp; - if (++cb->nblk < cb->maxblk) { + + cb->inp += cb->blksize; + if (cb->inp >= cb->end) + cb->inp = cb->start; + cb->stamp += cb->blksize; + if (cb->mmapped) { #ifdef AUDIO_DEBUG - if (audiodebug > 2) - Dprintf("audio_rint: tp=%p cc=%d\n", tp, cc); + if (audiodebug > 2) + printf("audio_rint: mmapped inp=%p cc=%d\n", + cb->inp, cb->blksize); #endif - error = hw->start_input(sc->hw_hdl, tp, cc, - audio_rint, (void *)sc); - if (error) { - DPRINTF(("audio_rint: start failed: %d\n", - error)); - audio_clear(sc); + hw->start_output(sc->hw_hdl, cb->inp, cb->blksize, + audio_rint, (void *)sc); + return; + } + +#ifdef AUDIO_INTR_TIME + { + struct timeval tv; + u_long t; + microtime(&tv); + t = tv.tv_usec + 1000000 * tv.tv_sec; + if (sc->sc_rnintr) { + long lastdelta, totdelta; + lastdelta = t - sc->sc_rlastintr - sc->sc_rblktime; + if (lastdelta > sc->sc_rblktime / 5) { + printf("audio: record interrupt(%d) off relative by %ld us (%lu)\n", + sc->sc_rnintr, lastdelta, sc->sc_rblktime); } - cb->au_stamp += sc->sc_smpl_in_blk; - } else { - /* - * XXX - * How do we count dropped input samples due to overrun? - * Start a "dummy DMA transfer" when the input ring buffer - * is full and count # of these? Seems pretty lame to - * me, but how else are we going to do this? - */ - cb->cb_drops++; - sc->sc_rbus = 0; - DPRINTF(("audio_rint: drops %d\n", cb->cb_drops)); - } - cb->tp = tp; - - audio_wakeup(&sc->sc_rchan); - selwakeup(&sc->sc_rsel); - if (sc->sc_async) - psignal(sc->sc_async, SIGIO); + totdelta = t - sc->sc_rfirstintr - sc->sc_rblktime * sc->sc_rnintr; + if (totdelta > sc->sc_rblktime / 2) { + sc->sc_rnintr++; + printf("audio: record interrupt(%d) off absolute by %ld us (%lu)\n", + sc->sc_rnintr, totdelta, sc->sc_rblktime); + sc->sc_rnintr++; /* avoid repeated messages */ + } + } else + sc->sc_rfirstintr = t; + sc->sc_rlastintr = t; + sc->sc_rnintr++; } +#endif + + cb->used += cb->blksize; + if (cb->pause) { + DPRINTF(("audio_rint: pdrops %lu\n", cb->pdrops)); + cb->pdrops += cb->blksize; + cb->outp += cb->blksize; + cb->used -= cb->blksize; + } else if (cb->used + cb->blksize >= cb->usedhigh && !cb->copying) { + DPRINTF(("audio_rint: drops %lu\n", cb->drops)); + cb->drops += cb->blksize; + cb->outp += cb->blksize; + cb->used -= cb->blksize; + } + +#ifdef AUDIO_DEBUG + if (audiodebug > 2) + printf("audio_rint: inp=%p cc=%d used=%d\n", + cb->inp, cb->blksize, cb->used); +#endif + error = hw->start_input(sc->hw_hdl, cb->inp, cb->blksize, + audio_rint, (void *)sc); + if (error) { + DPRINTF(("audio_rint: restart failed: %d\n", error)); + audio_clear(sc); + } + + audio_wakeup(&sc->sc_rchan); + selwakeup(&sc->sc_rsel); + if (sc->sc_async) + psignal(sc->sc_async, SIGIO); } int @@ -1558,11 +1769,12 @@ audiosetinfo(sc, ai) { struct audio_prinfo *r = &ai->record, *p = &ai->play; int cleared = 0; - int s, bsize, error = 0; + int s, error = 0; struct audio_hw_if *hw = sc->hw_if; mixer_ctrl_t ct; struct audio_params pp, rp; int np, nr; + unsigned int blks; if (hw == 0) /* HW has not attached */ return(ENXIO); @@ -1602,28 +1814,47 @@ audiosetinfo(sc, ai) rp.channels = r->channels; nr++; } +#ifdef AUDIO_DEBUG + if (audiodebug && nr) + audio_print_params("Setting record params", &rp); + if (audiodebug && np) + audio_print_params("Setting play params", &pp); +#endif if (nr && (error = audio_check_params(&rp))) return error; if (np && (error = audio_check_params(&pp))) return error; if (nr) { - audio_clear(sc); - error = hw->set_params(sc->hw_hdl, AUMODE_RECORD, &rp, &sc->sc_pparams); + if (!cleared) + audio_clear(sc); + cleared = 1; + error = hw->set_params(sc->hw_hdl, AUMODE_RECORD, + &rp, &sc->sc_pparams); if (error) return (error); sc->sc_rparams = rp; - sc->sc_blksize = audio_calc_blksize(sc); } if (np) { if (!cleared) audio_clear(sc); cleared = 1; - error = hw->set_params(sc->hw_hdl, AUMODE_PLAY, &pp, &sc->sc_rparams); + error = hw->set_params(sc->hw_hdl, AUMODE_PLAY, + &pp, &sc->sc_rparams); if (error) return (error); sc->sc_pparams = pp; - sc->sc_blksize = audio_calc_blksize(sc); } + /* Play params can affect the record params, so recalculate blksize. */ + if (nr || np) { + audio_calc_blksize(sc, AUMODE_RECORD); + audio_calc_blksize(sc, AUMODE_PLAY); + } +#ifdef AUDIO_DEBUG + if (audiodebug > 1 && nr) + audio_print_params("After setting record params", &sc->sc_rparams); + if (audiodebug > 1 && np) + audio_print_params("After setting play params", &sc->sc_pparams); +#endif if (p->port != ~0) { if (!cleared) @@ -1663,7 +1894,7 @@ audiosetinfo(sc, ai) } if (p->pause != (u_char)~0) { - sc->pr.cb_pause = p->pause; + sc->sc_pr.pause = p->pause; if (!p->pause) { s = splaudio(); audiostartp(sc); @@ -1671,7 +1902,7 @@ audiosetinfo(sc, ai) } } if (r->pause != (u_char)~0) { - sc->rr.cb_pause = r->pause; + sc->sc_rr.pause = r->pause; if (!r->pause) { s = splaudio(); audiostartr(sc); @@ -1685,41 +1916,46 @@ audiosetinfo(sc, ai) audio_clear(sc); cleared = 1; - if (ai->blocksize == 0) - bsize = sc->sc_blksize; - else if (ai->blocksize > AU_RING_SIZE/2) - bsize = AU_RING_SIZE/2; - else - bsize = ai->blocksize; - bsize = hw->round_blocksize(sc->hw_hdl, bsize); - if (bsize > AU_RING_SIZE) - bsize = AU_RING_SIZE; - - sc->sc_blksize = bsize; + /* No need to check the blocksize, audio_initbufs() does that. */ + sc->sc_pr.blksize = ai->blocksize; + sc->sc_rr.blksize = ai->blocksize; } if (np || nr || ai->blocksize != ~0) { - audio_alloc_auzero(sc, sc->sc_blksize); - sc->sc_smpl_in_blk = sc->sc_blksize / (sc->sc_pparams.precision / NBBY); - sc->sc_50ms = 50 * sc->sc_pparams.sample_rate / 1000; audio_initbufs(sc); +#ifdef AUDIO_INTR_TIME + sc->sc_pnintr = 0; + sc->sc_pblktime = (u_long)( + (double)sc->sc_pr.blksize * 1e6 / + (double)(sc->sc_pparams.precision / NBBY * + sc->sc_pparams.channels * + sc->sc_pparams.sample_rate)); + DPRINTF(("audio: play blktime = %lu for %d\n", + sc->sc_pblktime, sc->sc_pr.blksize)); + sc->sc_rnintr = 0; + sc->sc_rblktime = (u_long)( + (double)sc->sc_rr.blksize * 1e6 / + (double)(sc->sc_rparams.precision / NBBY * + sc->sc_rparams.channels * + sc->sc_rparams.sample_rate)); + DPRINTF(("audio: record blktime = %lu for %d\n", + sc->sc_rblktime, sc->sc_rr.blksize)); +#endif } if (ai->hiwat != ~0) { - if ((unsigned)ai->hiwat > sc->pr.maxblk) - ai->hiwat = sc->pr.maxblk; - if (sc->sc_hiwat != 0) - sc->sc_hiwat = ai->hiwat; + blks = ai->hiwat; + if (blks > sc->sc_pr.maxblks) + blks = sc->sc_pr.maxblks; + if (blks < 1) + blks = 1; + sc->sc_pr.usedhigh = blks * sc->sc_pr.blksize; } if (ai->lowat != ~0) { - if ((unsigned)ai->lowat > sc->pr.maxblk) - ai->lowat = sc->pr.maxblk; - sc->sc_lowat = ai->lowat; - } - if (ai->backlog != ~0) { - if ((unsigned)ai->backlog > (sc->pr.maxblk/2)) - ai->backlog = sc->pr.maxblk/2; - sc->sc_backlog = ai->backlog; + blks = ai->lowat; + if (blks > sc->sc_pr.maxblks - 1) + blks = sc->sc_pr.maxblks - 1; + sc->sc_pr.usedlow = blks * sc->sc_pr.blksize; } if (ai->mode != ~0) { if (!cleared) @@ -1729,8 +1965,8 @@ audiosetinfo(sc, ai) sc->sc_mode = ai->mode; if (sc->sc_mode & AUMODE_PLAY) { audio_init_play(sc); - if (!hw->full_duplex) /* Play takes precedence */ - sc->sc_mode &= ~(AUMODE_RECORD); + if (!sc->sc_full_duplex) /* Play takes precedence */ + sc->sc_mode &= ~AUMODE_RECORD; } if (sc->sc_mode & AUMODE_RECORD) audio_init_record(sc); @@ -1791,25 +2027,34 @@ audiogetinfo(sc, ai) else p->gain = AUDIO_MAX_GAIN/2; - p->pause = sc->pr.cb_pause; - r->pause = sc->rr.cb_pause; - p->error = sc->pr.cb_drops != 0; - r->error = sc->rr.cb_drops != 0; + p->seek = sc->sc_pr.used; + r->seek = sc->sc_rr.used; + + p->samples = sc->sc_pr.stamp - sc->sc_pr.drops; + r->samples = sc->sc_rr.stamp - sc->sc_rr.drops; + + p->eof = sc->sc_eof; + r->eof = 0; - p->open = ((sc->sc_open & AUOPEN_WRITE) != 0); - r->open = ((sc->sc_open & AUOPEN_READ) != 0); + p->pause = sc->sc_pr.pause; + r->pause = sc->sc_rr.pause; - p->samples = sc->pr.au_stamp - sc->pr.cb_pdrops; - r->samples = sc->rr.au_stamp - sc->rr.cb_pdrops; + p->error = sc->sc_pr.drops != 0; + r->error = sc->sc_rr.drops != 0; - p->seek = sc->sc_wseek; - r->seek = sc->sc_rseek; + p->waiting = r->waiting = 0; /* open never hangs */ - ai->buffersize = AU_RING_SIZE; - ai->blocksize = sc->sc_blksize; - ai->hiwat = sc->sc_hiwat; - ai->lowat = sc->sc_lowat; - ai->backlog = sc->sc_backlog; + p->open = (sc->sc_open & AUOPEN_WRITE) != 0; + r->open = (sc->sc_open & AUOPEN_READ) != 0; + + p->active = sc->sc_pbus; + r->active = sc->sc_rbus; + + ai->buffersize = sc->sc_pr.bufsize; + ai->blocksize = sc->sc_pr.blksize; + ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize; + ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize; + ai->backlog = 0; /* unused */ ai->mode = sc->sc_mode; return (0); @@ -1826,7 +2071,6 @@ mixer_open(dev, flags, ifmt, p) { int unit = AUDIOUNIT(dev); struct audio_softc *sc; - struct audio_hw_if *hw; if (unit >= naudio || !audio_softc[unit]) { DPRINTF(("mixer_open: invalid device unit - %d\n", unit)); @@ -1834,10 +2078,9 @@ mixer_open(dev, flags, ifmt, p) } sc = audio_softc[unit]; - hw = sc->hw_if; - DPRINTF(("mixer_open: dev=%x flags=0x%x sc=0x%x\n", dev, flags, sc)); - if (hw == 0) /* Hardware has not attached to us... */ + DPRINTF(("mixer_open: dev=%x flags=0x%x sc=%p\n", dev, flags, sc)); + if (sc->hw_if == 0) /* Hardware has not attached to us... */ return (ENXIO); return (0); diff --git a/sys/dev/audio_if.h b/sys/dev/audio_if.h index acca33dab90..890d1c5ccc9 100644 --- a/sys/dev/audio_if.h +++ b/sys/dev/audio_if.h @@ -1,4 +1,4 @@ -/* $NetBSD: audio_if.h,v 1.13 1997/05/20 12:51:45 augustss Exp $ */ +/* $NetBSD: audio_if.h,v 1.14 1997/07/27 01:16:46 augustss Exp $ */ /* * Copyright (c) 1994 Havard Eidnes. @@ -89,6 +89,8 @@ struct audio_hw_if { int (*commit_settings)__P((void *)); /* Start input/output routines. These usually control DMA. */ + int (*init_output)__P((void *, void *, int)); + int (*init_input)__P((void *, void *, int)); int (*start_output)__P((void *, void *, int, void (*)(void *), void *)); int (*start_input)__P((void *, void *, int, @@ -111,7 +113,12 @@ struct audio_hw_if { int (*query_devinfo)__P((void *, mixer_devinfo_t *)); - int full_duplex; /* non-null if HW is able to do full-duplex */ + /* Allocate/free memory for the ring buffer. Usually malloc/free. */ + void *(*alloc)__P((void *, unsigned long, int, int)); + void (*free)__P((void *, void *, int)); + unsigned long (*roundbuffer)__P((void *, unsigned long)); + + int props; /* device properties */ int audio_unit; }; diff --git a/sys/dev/audiovar.h b/sys/dev/audiovar.h index 9578c46f218..8a33af81efe 100644 --- a/sys/dev/audiovar.h +++ b/sys/dev/audiovar.h @@ -1,4 +1,4 @@ -/* $NetBSD: audiovar.h,v 1.10 1997/04/29 21:01:47 augustss Exp $ */ +/* $NetBSD: audiovar.h,v 1.11 1997/07/27 01:16:47 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -42,52 +42,38 @@ #define AUDIO_BLK_MS 20 /* 20 ms */ #endif -#ifndef AUDIO_BACKLOG -#define AUDIO_BACKLOG 3 /* 60 ms */ -#endif - -/* - * Use a single page as the size of the audio ring buffers, so that - * the data won't cross a page boundary. This way the dma carried out - * in the hardware module will be efficient (i.e., at_dma() won't have - * to make a copy). - */ #ifndef AU_RING_SIZE -#define AU_RING_SIZE NBPG +#define AU_RING_SIZE 65536 #endif -#define AU_RING_MOD(k) ((k) & (AU_RING_SIZE - 1)) -#define AU_RING_EMPTY(rp) ((rp)->hp == (rp)->tp) -#define AU_RING_FULL(rp) (AU_RING_MOD((rp)->tp + 1) == (rp)->hp) -#define AU_RING_LEN(rp) (AU_RING_MOD((rp)->tp - (rp)->hp)) -#define AU_RING_INIT(rp) { \ - (rp)->nblk = (rp)->au_stamp = 0; \ - (rp)->hp = (rp)->tp = (rp)->bp; \ - } - -struct audio_buffer { - u_char *hp; /* head */ - u_char *tp; /* tail */ - u_char *bp; /* start of buffer */ - u_char *ep; /* end of buffer */ - - int nblk; /* number of active blocks in buffer */ - int maxblk; /* max # of active blocks in buffer */ - u_long au_stamp; /* number of audio samples read/written */ - - u_short cb_pause; /* io paused */ - u_long cb_drops; /* missed samples from over/underrun */ - u_long cb_pdrops; /* paused samples */ - - int fill; /* number of silence pad bytes */ - u_char *otp; /* point where silence padding started */ +#define AUMINBUF 512 +#define AUMINNOBLK 3 +struct audio_ringbuffer { + int bufsize; /* allocated memory */ + int blksize; /* I/O block size */ + int maxblks; /* no of blocks in ring */ + u_char *start; /* start of buffer area */ + u_char *end; /* end of buffer area */ + u_char *inp; /* input pointer (to buffer) */ + u_char *outp; /* output pointer (from buffer) */ + int used; /* no of used bytes */ + int usedlow; /* start writer when used falls below this */ + int usedhigh; /* stop writer when used goes above this */ + u_long stamp; /* bytes transferred */ + u_long stamp_last; /* old value of bytes transferred */ + u_long drops; /* missed samples from over/underrun */ + u_long pdrops; /* paused samples */ + char pause; /* transfer is paused */ + char copying; /* data is being copied */ + char needfill; /* buffer needs filling when copying is done */ + char mmapped; /* device is mmap()-ed */ }; /* * Software state, per audio device. */ struct audio_softc { - void *hw_hdl; /* Hardware driver handle */ + void *hw_hdl; /* Hardware driver handle */ struct audio_hw_if *hw_if; /* Hardware interface */ u_char sc_open; /* single use device */ #define AUOPEN_READ 0x01 @@ -103,26 +89,32 @@ struct audio_softc { int sc_wchan; /* Ring buffers, separate for record and play. */ - struct audio_buffer rr; /* Record ring */ - struct audio_buffer pr; /* Play ring */ + struct audio_ringbuffer sc_rr; /* Record ring */ + struct audio_ringbuffer sc_pr; /* Play ring */ + + u_char *sc_sil_start; /* start of silence in buffer */ + int sc_sil_count; /* # of silence bytes */ - u_char *auzero_block; /* a block of silence */ - u_char sc_rbus; /* input dma in progress */ u_char sc_pbus; /* output dma in progress */ - u_long sc_wseek; /* timestamp of last frame written */ - u_long sc_rseek; /* timestamp of last frame read */ - - int sc_blksize; /* recv block (chunk) size in bytes */ - int sc_smpl_in_blk; /* # samples in a block */ - int sc_50ms; /* # of samples for 50ms? */ - int sc_backlog; /* # blks of xmit backlog to generate */ - int sc_lowat; /* xmit low water mark (for wakeup) */ - int sc_hiwat; /* xmit high water mark (for wakeup) */ - - int sc_rblks; /* number of phantom record blocks */ - int sc_wblks; /* number of output silence blocks */ struct audio_params sc_pparams; /* play encoding parameters */ struct audio_params sc_rparams; /* record encoding parameters */ + + int sc_eof; /* EOF, i.e. zero sixed write, counter */ + u_long sc_wstamp; + u_long sc_playdrop; + + int sc_full_duplex; /* device in full duplex mode */ + +#ifdef AUDIO_INTR_TIME + u_long sc_pfirstintr; /* first time we saw a xmit interrupt */ + int sc_pnintr; /* number of interrupts */ + u_long sc_plastintr; /* last time we saw a xmit interrupt */ + long sc_pblktime; /* nominal time between interrupts */ + u_long sc_rfirstintr; /* first time we saw a rec interrupt */ + int sc_rnintr; /* number of interrupts */ + u_long sc_rlastintr; /* last time we saw a xrec interrupt */ + long sc_rblktime; /* nominal time between interrupts */ +#endif }; diff --git a/sys/dev/ic/am7930.c b/sys/dev/ic/am7930.c index b87597eb169..11ac062203c 100644 --- a/sys/dev/ic/am7930.c +++ b/sys/dev/ic/am7930.c @@ -1,4 +1,4 @@ -/* $NetBSD: am7930.c,v 1.22 1997/05/24 20:15:59 pk Exp $ */ +/* $NetBSD: am7930.c,v 1.23 1997/07/27 01:16:37 augustss Exp $ */ /* * Copyright (c) 1995 Rolf Grossmann @@ -240,6 +240,8 @@ struct audio_hw_if sa_hw_if = { amd7930_set_in_port, amd7930_get_in_port, amd7930_commit_settings, + NULL, + NULL, amd7930_start_output, amd7930_start_input, amd7930_halt_output, @@ -252,7 +254,10 @@ struct audio_hw_if sa_hw_if = { amd7930_set_port, amd7930_get_port, amd7930_query_devinfo, - 1, + 0, + 0, + 0, + AUDIO_PROP_FULLDUPLEX, 0 }; diff --git a/sys/dev/isa/ad1848.c b/sys/dev/isa/ad1848.c index 10ef0b52200..337d8dbe7d6 100644 --- a/sys/dev/isa/ad1848.c +++ b/sys/dev/isa/ad1848.c @@ -1,4 +1,4 @@ -/* $NetBSD: ad1848.c,v 1.32 1997/07/15 07:46:14 augustss Exp $ */ +/* $NetBSD: ad1848.c,v 1.33 1997/07/27 01:16:50 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -97,8 +97,7 @@ #include <dev/isa/cs4231var.h> #ifdef AUDIO_DEBUG -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (ad1848debug) Dprintf x +#define DPRINTF(x) if (ad1848debug) printf x int ad1848debug = 0; #else #define DPRINTF(x) @@ -265,8 +264,8 @@ ad1848_dump_regs(sc) r = ad_read(sc, i); printf("%02x ", r); } - printf("\n"); } + printf("\n"); } #endif @@ -314,7 +313,7 @@ ad1848_probe(sc) return 0; } - /* map the ports upto the AD1488 port */ + /* Map the AD1848 ports */ if (bus_space_map(sc->sc_iot, sc->sc_iobase, AD1848_NPORT, 0, &sc->sc_ioh)) return 0; @@ -496,6 +495,8 @@ ad1848_attach(sc) struct audio_params xparams; sc->sc_locked = 0; + sc->sc_playrun = NOTRUNNING; + sc->sc_recrun = NOTRUNNING; if (sc->sc_drq != -1) { if (isa_dmamap_create(sc->sc_isa, sc->sc_drq, MAXPHYS /* XXX */, @@ -1010,7 +1011,7 @@ ad1848_set_params(addr, mode, p, q) int error, bits, enc; void (*swcode) __P((void *, u_char *buf, int cnt)); - DPRINTF(("ad1848_set_params: %d %d %d %d\n", + DPRINTF(("ad1848_set_params: %d %d %d %ld\n", p->encoding, p->precision, p->channels, p->sample_rate)); enc = p->encoding; @@ -1094,7 +1095,7 @@ ad1848_set_params(addr, mode, p, q) q->channels = p->channels; q->precision = p->precision; - DPRINTF(("ad1848_set_params succeeded\n")); + DPRINTF(("ad1848_set_params succeeded, bits=%x\n", bits)); return (0); } @@ -1167,7 +1168,7 @@ ad1848_open(sc, dev, flags) dev_t dev; int flags; { - DPRINTF(("ad1848_open: sc=0x%x\n", sc)); + DPRINTF(("ad1848_open: sc=%p\n", sc)); sc->sc_intr = 0; sc->sc_lastcc = -1; @@ -1198,12 +1199,21 @@ ad1848_close(addr) sc->sc_intr = 0; DPRINTF(("ad1848_close: stop DMA\n")); + if (sc->sc_playrun != NOTRUNNING) { + isa_dmaabort(sc->sc_isa, sc->sc_drq); + sc->sc_playrun = NOTRUNNING; + } + if (sc->sc_recrun != NOTRUNNING) { + isa_dmaabort(sc->sc_isa, sc->sc_recdrq); + sc->sc_recrun = NOTRUNNING; + } ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)0); ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)0); /* Disable interrupts */ DPRINTF(("ad1848_close: disable intrs\n")); - ad_write(sc, SP_PIN_CONTROL, ad_read(sc, SP_PIN_CONTROL) & ~(INTERRUPT_ENABLE)); + ad_write(sc, SP_PIN_CONTROL, + ad_read(sc, SP_PIN_CONTROL) & ~INTERRUPT_ENABLE); DPRINTF(("ad1848_close: disable capture and playback\n")); r = ad_read(sc, SP_INTERFACE_CONFIG); @@ -1460,6 +1470,24 @@ ad1848_cont_in_dma(addr) return(0); } +int +ad1848_dma_init_input(addr, buf, cc) + void *addr; + void *buf; + int cc; +{ + struct ad1848_softc *sc = addr; + + sc->sc_recrun = DMARUNNING; + sc->sc_dma_flags = DMAMODE_READ | DMAMODE_LOOP; + sc->sc_dma_bp = buf; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_recdrq, buf, cc, NULL, + sc->sc_dma_flags, BUS_DMA_NOWAIT); + DPRINTF(("ad1848_dma_init_input: %p %d\n", buf, cc)); + return 0; +} + /* * DMA input/output are called at splaudio(). */ @@ -1481,44 +1509,74 @@ ad1848_dma_input(addr, p, cc, intr, arg) #ifdef AUDIO_DEBUG if (ad1848debug > 1) - Dprintf("ad1848_dma_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + printf("ad1848_dma_input: cc=%d %p (%p)\n", cc, intr, arg); #endif sc->sc_locked = 1; sc->sc_intr = intr; sc->sc_arg = arg; - sc->sc_dma_flags = DMAMODE_READ; - sc->sc_dma_bp = p; - sc->sc_dma_cnt = cc; - isa_dmastart(sc->sc_isa, sc->sc_recdrq, p, cc, NULL, - DMAMODE_READ, BUS_DMA_NOWAIT); - if (sc->precision == 16) - cc >>= 1; - - if (sc->channels == 2) - cc >>= 1; - cc--; + switch (sc->sc_recrun) { + case NOTRUNNING: + sc->sc_dma_flags = DMAMODE_READ; + sc->sc_dma_bp = p; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_recdrq, p, cc, NULL, + DMAMODE_READ, BUS_DMA_NOWAIT); + goto startpcm; + case DMARUNNING: + sc->sc_recrun = PCMRUNNING; + startpcm: + if (sc->precision == 16) + cc >>= 1; + if (sc->channels == 2) + cc >>= 1; + cc--; - if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_RECORD) { - ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); - ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); + if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_RECORD) { + ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); + ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); - if (sc->mode == 2) { - ad_write(sc, CS_LOWER_REC_CNT, (u_char)(cc & 0xff)); - ad_write(sc, CS_UPPER_REC_CNT, (u_char)((cc >> 8) & 0xff)); - } + if (sc->mode == 2) { + ad_write(sc, CS_LOWER_REC_CNT, (u_char)(cc & 0xff)); + ad_write(sc, CS_UPPER_REC_CNT, (u_char)((cc >> 8) & 0xff)); + } - reg = ad_read(sc, SP_INTERFACE_CONFIG); - ad_write(sc, SP_INTERFACE_CONFIG, (CAPTURE_ENABLE|reg)); + reg = ad_read(sc, SP_INTERFACE_CONFIG); + ad_write(sc, SP_INTERFACE_CONFIG, (CAPTURE_ENABLE|reg)); - sc->sc_lastcc = cc; - sc->sc_mode = AUMODE_RECORD; + sc->sc_lastcc = cc; + sc->sc_mode = AUMODE_RECORD; +#ifdef AUDIO_DEBUG + if (ad1848debug > 1) + printf("ad1848_dma_input: started capture\n"); +#endif + } + case PCMRUNNING: + break; } return 0; } int +ad1848_dma_init_output(addr, buf, cc) + void *addr; + void *buf; + int cc; +{ + struct ad1848_softc *sc = addr; + + sc->sc_playrun = DMARUNNING; + sc->sc_dma_flags = DMAMODE_WRITE | DMAMODE_LOOP; + sc->sc_dma_bp = buf; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_drq, buf, cc, NULL, + sc->sc_dma_flags, BUS_DMA_NOWAIT); + DPRINTF(("ad1848_dma_init_output: %p %d\n", buf, cc)); + return 0; +} + +int ad1848_dma_output(addr, p, cc, intr, arg) void *addr; void *p; @@ -1535,32 +1593,43 @@ ad1848_dma_output(addr, p, cc, intr, arg) } #ifdef AUDIO_DEBUG - if (ad1848debug > 1) - Dprintf("ad1848_dma_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + if (ad1848debug > 0) + printf("ad1848_dma_output: cc=%d at %p 0x%p (0x%p)\n", cc, p, intr, arg); #endif sc->sc_locked = 1; sc->sc_intr = intr; sc->sc_arg = arg; - sc->sc_dma_flags = DMAMODE_WRITE; - sc->sc_dma_bp = p; - sc->sc_dma_cnt = cc; - isa_dmastart(sc->sc_isa, sc->sc_drq, p, cc, NULL, - DMAMODE_WRITE, BUS_DMA_NOWAIT); - - if (sc->precision == 16) - cc >>= 1; - - if (sc->channels == 2) - cc >>= 1; - cc--; - - if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_PLAY) { - ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); - ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); - reg = ad_read(sc, SP_INTERFACE_CONFIG); - ad_write(sc, SP_INTERFACE_CONFIG, (PLAYBACK_ENABLE|reg)); - sc->sc_lastcc = cc; - sc->sc_mode = AUMODE_PLAY; + + switch (sc->sc_playrun) { + case NOTRUNNING: + sc->sc_dma_flags = DMAMODE_WRITE; + sc->sc_dma_bp = p; + sc->sc_dma_cnt = cc; + isa_dmastart(sc->sc_isa, sc->sc_drq, p, cc, NULL, + DMAMODE_WRITE, BUS_DMA_NOWAIT); + goto startpcm; + case DMARUNNING: + sc->sc_playrun = PCMRUNNING; + startpcm: + if (sc->precision == 16) + cc >>= 1; + if (sc->channels == 2) + cc >>= 1; + cc--; + + if (sc->sc_lastcc != cc || sc->sc_mode != AUMODE_PLAY) { + ad_write(sc, SP_LOWER_BASE_COUNT, (u_char)(cc & 0xff)); + ad_write(sc, SP_UPPER_BASE_COUNT, (u_char)((cc >> 8) & 0xff)); + + reg = ad_read(sc, SP_INTERFACE_CONFIG); + ad_write(sc, SP_INTERFACE_CONFIG, (PLAYBACK_ENABLE|reg)); + + sc->sc_lastcc = cc; + sc->sc_mode = AUMODE_PLAY; + } + break; + case PCMRUNNING: + break; } return 0; @@ -1579,7 +1648,7 @@ ad1848_intr(arg) #ifdef AUDIO_DEBUG if (ad1848debug > 1) - Dprintf("ad1848_intr: intr=0x%x status=%x\n", sc->sc_intr, status); + printf("ad1848_intr: intr=%p status=%x\n", sc->sc_intr, status); #endif sc->sc_locked = 0; sc->sc_interrupts++; @@ -1588,7 +1657,7 @@ ad1848_intr(arg) if (sc->sc_intr && (status & INTERRUPT_STATUS)) { /* ACK DMA read because it may be in a bounce buffer */ /* XXX Do write to mask DMA ? */ - if (sc->sc_dma_flags & DMAMODE_READ) + if ((sc->sc_dma_flags & DMAMODE_READ) && sc->sc_recrun == NOTRUNNING) isa_dmadone(sc->sc_isa, sc->sc_recdrq); (*sc->sc_intr)(sc->sc_arg); retval = 1; @@ -1600,3 +1669,34 @@ ad1848_intr(arg) return(retval); } + +void * +ad1848_malloc(addr, size, pool, flags) + void *addr; + unsigned long size; + int pool; + int flags; +{ + struct ad1848_softc *sc = addr; + + return isa_malloc(sc->sc_isa, 4, size, pool, flags); +} + +void +ad1848_free(addr, ptr, pool) + void *addr; + void *ptr; + int pool; +{ + isa_free(ptr, pool); +} + +unsigned long +ad1848_round(addr, size) + void *addr; + unsigned long size; +{ + if (size > MAX_ISADMA) + size = MAX_ISADMA; + return size; +} diff --git a/sys/dev/isa/ad1848var.h b/sys/dev/isa/ad1848var.h index cd3a9b1649f..1c52658cd35 100644 --- a/sys/dev/isa/ad1848var.h +++ b/sys/dev/isa/ad1848var.h @@ -1,4 +1,4 @@ -/* $NetBSD: ad1848var.h,v 1.15 1997/06/06 23:43:46 thorpej Exp $ */ +/* $NetBSD: ad1848var.h,v 1.16 1997/07/27 01:16:52 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -62,6 +62,12 @@ struct ad1848_softc { u_int sc_dma_cnt; #endif + char sc_playrun; /* running in continuous mode */ + char sc_recrun; /* running in continuous mode */ +#define NOTRUNNING 0 +#define DMARUNNING 1 +#define PCMRUNNING 2 + int sc_iobase; /* I/O port base address */ int sc_irq; /* interrupt */ int sc_drq; /* DMA */ @@ -113,6 +119,8 @@ int ad1848_set_params __P((void *, int, struct audio_params *, struct audio_para int ad1848_round_blocksize __P((void *, int)); +int ad1848_dma_init_output __P((void *, void *, int)); +int ad1848_dma_init_input __P((void *, void *, int)); int ad1848_dma_output __P((void *, void *, int, void (*)(void *), void*)); int ad1848_dma_input __P((void *, void *, int, void (*)(void *), void*)); @@ -143,4 +151,9 @@ int ad1848_set_mic_gain __P((struct ad1848_softc *, struct ad1848_volume *)); int ad1848_get_mic_gain __P((struct ad1848_softc *, struct ad1848_volume *)); void ad1848_mute_aux1 __P((struct ad1848_softc *, int /* onoff */)); void ad1848_mute_aux2 __P((struct ad1848_softc *, int /* onoff */)); + +void *ad1848_malloc __P((void *, unsigned long, int, int)); +void ad1848_free __P((void *, void *, int)); +unsigned long ad1848_round __P((void *, unsigned long)); + #endif diff --git a/sys/dev/isa/gus.c b/sys/dev/isa/gus.c index 02883f3e5ac..e918706fa12 100644 --- a/sys/dev/isa/gus.c +++ b/sys/dev/isa/gus.c @@ -1,4 +1,4 @@ -/* $NetBSD: gus.c,v 1.32 1997/07/15 07:46:16 augustss Exp $ */ +/* $NetBSD: gus.c,v 1.33 1997/07/27 01:16:55 augustss Exp $ */ /*- * Copyright (c) 1996 The NetBSD Foundation, Inc. @@ -319,9 +319,8 @@ struct ics2101_volume { #ifdef AUDIO_DEBUG #define GUSPLAYDEBUG /*XXX*/ -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (gusdebug) Dprintf x -#define DMAPRINTF(x) if (gusdmadebug) Dprintf x +#define DPRINTF(x) if (gusdebug) printf x +#define DMAPRINTF(x) if (gusdmadebug) printf x int gusdebug = 0; int gusdmadebug = 0; #else @@ -611,6 +610,9 @@ struct audio_hw_if gus_hw_if = { gus_commit_settings, + NULL, + NULL, + gus_dma_output, gus_dma_input, gus_halt_out_dma, @@ -625,7 +627,10 @@ struct audio_hw_if gus_hw_if = { gus_mixer_set_port, gus_mixer_get_port, gus_mixer_query_devinfo, - 1, /* full-duplex */ + NULL, + NULL, + NULL, + AUDIO_PROP_FULLDUPLEX, 0, }; @@ -888,10 +893,10 @@ gusattach(parent, self, aux) printf("%s codec/mixer, ", sc->sc_codec.chip_name); if (sc->sc_recdrq == sc->sc_drq) { printf("half-duplex"); - gus_hw_if.full_duplex = 0; + gus_hw_if.props &= ~AUDIO_PROP_FULLDUPLEX; } else { printf("full-duplex, record drq %d", sc->sc_recdrq); - gus_hw_if.full_duplex = 1; + gus_hw_if.props |= AUDIO_PROP_FULLDUPLEX; } printf(">\n"); @@ -1117,7 +1122,7 @@ gus_dma_output(addr, buf, size, intr, arg) u_long boarddma; int flags; - DMAPRINTF(("gus_dma_output %d @ %x\n", size, buf)); + DMAPRINTF(("gus_dma_output %d @ %p\n", size, buf)); if (size != sc->sc_blocksize) { DPRINTF(("gus_dma_output reqsize %d not sc_blocksize %d\n", @@ -1210,7 +1215,7 @@ gusclose(addr) { struct gus_softc *sc = addr; - DPRINTF(("gus_close: sc=0x%x\n", sc)); + DPRINTF(("gus_close: sc=%p\n", sc)); /* if (sc->sc_flags & GUS_DMAOUT_ACTIVE) */ { @@ -1365,7 +1370,7 @@ gus_dmaout_dointr(sc) /* sc->sc_dmaoutcnt - 1 because DMA controller counts from zero?. */ isa_dmadone(sc->sc_dev.dv_parent, sc->sc_drq); sc->sc_flags &= ~GUS_DMAOUT_ACTIVE; /* pending DMA is done */ - DMAPRINTF(("gus_dmaout_dointr %d @ %x\n", sc->sc_dmaoutcnt, + DMAPRINTF(("gus_dmaout_dointr %d @ %p\n", sc->sc_dmaoutcnt, sc->sc_dmaoutaddr)); /* @@ -2519,7 +2524,7 @@ gus_get_curaddr(sc, voice) if (sc->sc_voc[voice].voccntl & GUSMASK_DATA_SIZE16) addr = (addr & 0xc0000) | ((addr & 0x1ffff) << 1); /* undo 16-bit change */ - DPRINTF(("gus voice %d curaddr %d end_addr %d\n", + DPRINTF(("gus voice %d curaddr %ld end_addr %ld\n", voice, addr, sc->sc_voc[voice].end_addr)); /* XXX sanity check the address? */ @@ -2774,6 +2779,9 @@ gus_init_cs4231(sc) gusmax_commit_settings, + NULL, + NULL, + gusmax_dma_output, gusmax_dma_input, gusmax_halt_out_dma, @@ -2788,7 +2796,10 @@ gus_init_cs4231(sc) gusmax_mixer_set_port, gusmax_mixer_get_port, gusmax_mixer_query_devinfo, - 1, /* full-duplex */ + NULL, + NULL, + NULL, + AUDIO_PROP_FULLDUPLEX, 0, }; sc->sc_flags |= GUS_CODEC_INSTALLED; @@ -3029,7 +3040,7 @@ gus_dmain_intr(sc) sc->sc_inarg = 0; sc->sc_flags &= ~GUS_DMAIN_ACTIVE; - DMAPRINTF(("calling dmain_intr callback %x(%x)\n", callback, arg)); + DMAPRINTF(("calling dmain_intr callback %p(%p)\n", callback, arg)); (*callback)(arg); return 1; } else { @@ -3157,9 +3168,6 @@ gus_setfd(addr, flag) void *addr; int flag; { - if (gus_hw_if.full_duplex == 0) - return ENOTTY; - return(0); /* nothing fancy to do. */ } diff --git a/sys/dev/isa/isadma.c b/sys/dev/isa/isadma.c index 31f921851fc..c8439843fbb 100644 --- a/sys/dev/isa/isadma.c +++ b/sys/dev/isa/isadma.c @@ -1,4 +1,4 @@ -/* $NetBSD: isadma.c,v 1.26 1997/06/06 23:43:55 thorpej Exp $ */ +/* $NetBSD: isadma.c,v 1.27 1997/07/27 01:16:57 augustss Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -55,6 +55,17 @@ #include <dev/isa/isadmavar.h> #include <dev/isa/isadmareg.h> +/* Used by isa_malloc() */ +#include <sys/malloc.h> +struct isa_mem { + struct device *isadev; + int chan; + bus_size_t size; + bus_addr_t addr; + caddr_t kva; + struct isa_mem *next; +} *isa_mem_head = 0; + /* * High byte of DMA address is stored in this DMAPG register for * the Nth DMA channel. @@ -571,3 +582,61 @@ isa_dmamem_mmap(isadev, chan, addr, size, off, prot, flags) return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags)); } + +void * +isa_malloc(isadev, chan, size, pool, flags) + struct device *isadev; + int chan; + size_t size; + int pool; + int flags; +{ + bus_addr_t addr; + caddr_t kva; + int bflags; + struct isa_mem *m; + + bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT; + + if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags)) + return 0; + if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) { + isa_dmamem_free(isadev, chan, addr, size); + return 0; + } + m = malloc(sizeof(*m), pool, flags); + if (m == 0) { + isa_dmamem_unmap(isadev, chan, kva, size); + isa_dmamem_free(isadev, chan, addr, size); + return 0; + } + m->isadev = isadev; + m->chan = chan; + m->size = size; + m->addr = addr; + m->kva = kva; + m->next = isa_mem_head; + isa_mem_head = m; + return (void *)kva; +} + +void +isa_free(addr, pool) + void *addr; + int pool; +{ + struct isa_mem **mp, *m; + caddr_t kva = (caddr_t)addr; + + for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next) + ; + m = *mp; + if (!m) { + printf("isa_free: freeing unallocted memory\n"); + return; + } + *mp = m->next; + isa_dmamem_unmap(m->isadev, m->chan, kva, m->size); + isa_dmamem_free(m->isadev, m->chan, m->addr, m->size); + free(m, pool); +} diff --git a/sys/dev/isa/isadmavar.h b/sys/dev/isa/isadmavar.h index 2edea86feef..7e8a4457043 100644 --- a/sys/dev/isa/isadmavar.h +++ b/sys/dev/isa/isadmavar.h @@ -1,4 +1,4 @@ -/* $NetBSD: isadmavar.h,v 1.7 1997/06/06 23:43:56 thorpej Exp $ */ +/* $NetBSD: isadmavar.h,v 1.8 1997/07/27 01:17:01 augustss Exp $ */ /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. @@ -37,6 +37,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#define MAX_ISADMA 65536 + #define DMAMODE_WRITE 0 #define DMAMODE_READ 1 #define DMAMODE_LOOP 2 @@ -63,3 +65,7 @@ int isa_dmamem_map __P((struct device *, int, bus_addr_t, bus_size_t, void isa_dmamem_unmap __P((struct device *, int, caddr_t, size_t)); int isa_dmamem_mmap __P((struct device *, int, bus_addr_t, bus_size_t, int, int, int)); + +void *isa_malloc __P((struct device *, int, size_t, int, int)); +void isa_free __P((void *, int)); + diff --git a/sys/dev/isa/pas.c b/sys/dev/isa/pas.c index 058b0e586dc..5aa05ad2cdf 100644 --- a/sys/dev/isa/pas.c +++ b/sys/dev/isa/pas.c @@ -1,4 +1,4 @@ -/* $NetBSD: pas.c,v 1.28 1997/07/25 01:42:20 augustss Exp $ */ +/* $NetBSD: pas.c,v 1.29 1997/07/27 01:17:02 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -120,6 +120,8 @@ struct audio_hw_if pas_hw_if = { sbdsp_set_in_port, sbdsp_get_in_port, sbdsp_commit_settings, + NULL, + NULL, sbdsp_dma_output, sbdsp_dma_input, sbdsp_haltdma, @@ -132,7 +134,10 @@ struct audio_hw_if pas_hw_if = { sbdsp_mixer_set_port, sbdsp_mixer_get_port, sbdsp_mixer_query_devinfo, - 0, /* not full-duplex */ + sb_malloc, + sb_free, + sb_round, + 0, 0 }; diff --git a/sys/dev/isa/pss.c b/sys/dev/isa/pss.c index 590f8ccfbba..b0b9cf28527 100644 --- a/sys/dev/isa/pss.c +++ b/sys/dev/isa/pss.c @@ -1,4 +1,4 @@ -/* $NetBSD: pss.c,v 1.28 1997/06/06 23:43:59 thorpej Exp $ */ +/* $NetBSD: pss.c,v 1.29 1997/07/27 01:17:04 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -155,8 +155,7 @@ struct pcd_softc { #endif #ifdef AUDIO_DEBUG -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (pssdebug) Dprintf x +#define DPRINTF(x) if (pssdebug) printf x int pssdebug = 0; #else #define DPRINTF(x) @@ -243,6 +242,8 @@ struct audio_hw_if pss_audio_if = { pss_set_in_port, pss_get_in_port, ad1848_commit_settings, + NULL, + NULL, ad1848_dma_output, ad1848_dma_input, ad1848_halt_out_dma, @@ -255,7 +256,10 @@ struct audio_hw_if pss_audio_if = { pss_mixer_set_port, pss_mixer_get_port, pss_query_devinfo, - 0, /* not full-duplex */ + ad1848_malloc, + ad1848_free, + ad1848_round, + 0, 0 }; @@ -1348,7 +1352,7 @@ pssintr(arg) sr = inw(sc->sc_iobase+PSS_STATUS); - DPRINTF(("pssintr: sc=%x st=%x\n", sc, sr)); + DPRINTF(("pssintr: sc=%p st=%x\n", sc, sr)); /* Acknowledge intr */ outw(sc->sc_iobase+PSS_IRQ_ACK, 0); @@ -1384,7 +1388,7 @@ pss_getdev(addr, retp) void *addr; struct audio_device *retp; { - DPRINTF(("pss_getdev: retp=0x%x\n", retp)); + DPRINTF(("pss_getdev: retp=%p\n", retp)); *retp = pss_device; return 0; diff --git a/sys/dev/isa/sb.c b/sys/dev/isa/sb.c index 879ae2b00eb..a0af0d0372f 100644 --- a/sys/dev/isa/sb.c +++ b/sys/dev/isa/sb.c @@ -1,4 +1,4 @@ -/* $NetBSD: sb.c,v 1.49 1997/06/06 23:44:01 thorpej Exp $ */ +/* $NetBSD: sb.c,v 1.50 1997/07/27 01:17:05 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -86,6 +86,8 @@ struct audio_hw_if sb_hw_if = { sbdsp_set_in_port, sbdsp_get_in_port, sbdsp_commit_settings, + sbdsp_dma_init_output, + sbdsp_dma_init_input, sbdsp_dma_output, sbdsp_dma_input, sbdsp_haltdma, @@ -98,7 +100,10 @@ struct audio_hw_if sb_hw_if = { sbdsp_mixer_set_port, sbdsp_mixer_get_port, sbdsp_mixer_query_devinfo, - 0, /* not full-duplex */ + sb_malloc, + sb_free, + sb_round, + AUDIO_PROP_MMAP, 0 }; diff --git a/sys/dev/isa/sb_isa.c b/sys/dev/isa/sb_isa.c index 2e53a360ca7..8f5865b80ab 100644 --- a/sys/dev/isa/sb_isa.c +++ b/sys/dev/isa/sb_isa.c @@ -1,4 +1,4 @@ -/* $NetBSD: sb_isa.c,v 1.7 1997/06/06 23:44:01 thorpej Exp $ */ +/* $NetBSD: sb_isa.c,v 1.8 1997/07/27 01:17:06 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -102,7 +102,7 @@ sb_isa_match(parent, match, aux) sc->sc_iobase = ia->ia_iobase; sc->sc_irq = ia->ia_irq; sc->sc_drq8 = ia->ia_drq; - sc->sc_drq16 = 5; /* XXX XXX */ + sc->sc_drq16 = 5; /* XXX */ sc->sc_ic = ia->ia_ic; if (!sbmatch(sc)) { diff --git a/sys/dev/isa/sbdsp.c b/sys/dev/isa/sbdsp.c index 6fb46ba19e0..1f32315dbee 100644 --- a/sys/dev/isa/sbdsp.c +++ b/sys/dev/isa/sbdsp.c @@ -1,4 +1,4 @@ -/* $NetBSD: sbdsp.c,v 1.59 1997/07/15 07:46:19 augustss Exp $ */ +/* $NetBSD: sbdsp.c,v 1.60 1997/07/27 01:17:07 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -68,9 +68,10 @@ #include <dev/isa/sbreg.h> #include <dev/isa/sbdspvar.h> +#define MAXDMA 65536 /* XXX */ + #ifdef AUDIO_DEBUG -extern void Dprintf __P((const char *, ...)); -#define DPRINTF(x) if (sbdspdebug) Dprintf x +#define DPRINTF(x) if (sbdspdebug) printf x int sbdspdebug = 0; #else #define DPRINTF(x) @@ -367,6 +368,7 @@ sbdsp_attach(sc) sc->in_filter = 0; /* no filters turned on, please */ } + printf(" drq16 %d", sc->sc_drq16); printf(": dsp v%d.%02d%s\n", SBVER_MAJOR(sc->sc_version), SBVER_MINOR(sc->sc_version), sc->sc_model == SB_JAZZ ? ": <Jazz16>" : ""); @@ -614,8 +616,8 @@ sbdsp_set_params(addr, mode, p, q) */ sc->sc_dmadir = SB_DMA_NONE; - DPRINTF(("set_params: model=%d, rate=%ld, prec=%d, chan=%d, enc=%d -> tc=%02x, cmd=%02x, bmode=%02x, cmdchan=%02x, swcode=%p\n", - sc->sc_model, p->sample_rate, p->precision, p->channels, + DPRINTF(("set_params: model=%d, mode=%d, rate=%ld, prec=%d, chan=%d, enc=%d -> tc=%02x, cmd=%02x, bmode=%02x, cmdchan=%02x, swcode=%p\n", + sc->sc_model, mode, p->sample_rate, p->precision, p->channels, p->encoding, tc, m->cmd, bmode, m->cmdchan, swcode)); return 0; @@ -726,7 +728,7 @@ sbdsp_set_in_ports(sc, mask) sbport = SBP_FROM_CD; break; default: - return EINVAL; + return (EINVAL); } sbdsp_mix_write(sc, SBP_RECORD_SOURCE, SBP_RECORD_FROM(sbport, SBP_FILTER_OFF, SBP_IFILTER_HIGH)); @@ -799,12 +801,9 @@ sbdsp_round_blocksize(addr, blk) void *addr; int blk; { - if (blk > NBPG/3) - blk = NBPG/3; /* XXX allow at least 3 blocks */ - - /* Round to a multiple of the biggest sample size. */ - blk &= -4; - + if (blk > MAXDMA) + blk = MAXDMA; /* cannot DMA more than 64k */ + blk &= -4; /* round to biggest sample size */ return blk; } @@ -1023,8 +1022,8 @@ sbdsp_spkroff(sc) } /* - * Read the version number out of the card. Return major code - * in high byte, and minor code in low byte. + * Read the version number out of the card. + * Store version information in the softc. */ void sbversion(sc) @@ -1130,6 +1129,27 @@ sbdsp16_set_rate(sc, cmd, rate) } int +sbdsp_dma_init_input(addr, buf, cc) + void *addr; + void *buf; + int cc; +{ + struct sbdsp_softc *sc = addr; + + if (sc->sc_model == SB_1) + return 0; + sc->dmaflags = DMAMODE_READ | DMAMODE_LOOP; + sc->dmaaddr = buf; + sc->dmacnt = cc; + sc->dmachan = sc->sc_imodep->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; + DPRINTF(("sbdsp: dma start loop input addr=%p cc=%d chan=%d\n", + buf, cc, sc->dmachan)); + isa_dmastart(sc->sc_isa, sc->dmachan, sc->dmaaddr, + sc->dmacnt, NULL, sc->dmaflags, BUS_DMA_NOWAIT); + return 0; +} + +int sbdsp_dma_input(addr, p, cc, intr, arg) void *addr; void *p; @@ -1144,7 +1164,7 @@ sbdsp_dma_input(addr, p, cc, intr, arg) #ifdef AUDIO_DEBUG if (sbdspdebug > 1) - Dprintf("sbdsp_dma_input: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + printf("sbdsp_dma_input: cc=%d %p (%p)\n", cc, intr, arg); #endif #ifdef DIAGNOSTIC if (sc->sc_imodep->channels == 2 && (cc & 1)) { @@ -1165,33 +1185,39 @@ sbdsp_dma_input(addr, p, cc, intr, arg) if (ISSB16CLASS(sc)) { if (sbdsp16_set_rate(sc, SB_DSP16_INPUTRATE, - sc->sc_irate)) + sc->sc_irate)) { + DPRINTF(("sbdsp_dma_input: rate=%d set failed\n", + sc->sc_irate)); goto giveup; + } } else { - if (sbdsp_set_timeconst(sc, sc->sc_itc)) + if (sbdsp_set_timeconst(sc, sc->sc_itc)) { + DPRINTF(("sbdsp_dma_output: tc=%d set failed\n", + sc->sc_irate)); goto giveup; + } } sc->sc_dmadir = SB_DMA_IN; sc->dmaflags = DMAMODE_READ; - if (loop) - sc->dmaflags |= DMAMODE_LOOP; } else { - /* If already started; just return. */ + /* If already started just return. */ if (loop) return 0; } - sc->dmaaddr = p; - sc->dmacnt = loop ? (NBPG/cc)*cc : cc; - sc->dmachan = sc->sc_imodep->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; + if (!loop) { + sc->dmaaddr = p; + sc->dmacnt = cc; + sc->dmachan = sc->sc_imodep->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; #ifdef AUDIO_DEBUG - if (sbdspdebug > 1) - Dprintf("sbdsp_dma_input: dmastart %x %p %d %d\n", + if (sbdspdebug > 2) + printf("sbdsp_dma_input: dmastart %x %p %ld %d\n", sc->dmaflags, sc->dmaaddr, sc->dmacnt, sc->dmachan); #endif - isa_dmastart(sc->sc_isa, sc->dmachan, sc->dmaaddr, - sc->dmacnt, NULL, sc->dmaflags, BUS_DMA_NOWAIT); + isa_dmastart(sc->sc_isa, sc->dmachan, sc->dmaaddr, + sc->dmacnt, NULL, sc->dmaflags, BUS_DMA_NOWAIT); + } sc->sc_intr = intr; sc->sc_arg = arg; @@ -1200,6 +1226,11 @@ sbdsp_dma_input(addr, p, cc, intr, arg) cc >>= 1; --cc; if (ISSB16CLASS(sc)) { +#ifdef AUDIO_DEBUG + if (sbdspdebug > 2) + printf("sbdsp16 input command %02x %02x %d\n", + sc->sc_imodep->cmd, sc->sc_ibmode, cc); +#endif if (sbdsp_wdsp(sc, sc->sc_imodep->cmd) < 0 || sbdsp_wdsp(sc, sc->sc_ibmode) < 0 || sbdsp16_wait(sc) || @@ -1214,11 +1245,11 @@ sbdsp_dma_input(addr, p, cc, intr, arg) if (sbdsp_wdsp(sc, SB_DSP_BLOCKSIZE) < 0 || sbdsp_wdsp(sc, cc) < 0 || sbdsp_wdsp(sc, cc >> 8) < 0) { - DPRINTF(("sbdsp_dma_input: SB2 DMA start failed\n")); + DPRINTF(("sbdsp_dma_input: SB2 DMA blocksize failed\n")); goto giveup; } if (sbdsp_wdsp(sc, sc->sc_imodep->cmd) < 0) { - DPRINTF(("sbdsp_dma_input: SB2 DMA restart failed\n")); + DPRINTF(("sbdsp_dma_input: SB2 DMA start failed\n")); goto giveup; } } else { @@ -1242,6 +1273,27 @@ badmode: } int +sbdsp_dma_init_output(addr, buf, cc) + void *addr; + void *buf; + int cc; +{ + struct sbdsp_softc *sc = addr; + + if (sc->sc_model == SB_1) + return 0; + sc->dmaflags = DMAMODE_WRITE | DMAMODE_LOOP; + sc->dmaaddr = buf; + sc->dmacnt = cc; + sc->dmachan = sc->sc_omodep->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; + DPRINTF(("sbdsp: dma start loop output addr=%p cc=%d chan=%d\n", + buf, cc, sc->dmachan)); + isa_dmastart(sc->sc_isa, sc->dmachan, sc->dmaaddr, + sc->dmacnt, NULL, sc->dmaflags, BUS_DMA_NOWAIT); + return 0; +} + +int sbdsp_dma_output(addr, p, cc, intr, arg) void *addr; void *p; @@ -1256,7 +1308,7 @@ sbdsp_dma_output(addr, p, cc, intr, arg) #ifdef AUDIO_DEBUG if (sbdspdebug > 1) - Dprintf("sbdsp_dma_output: cc=%d 0x%x (0x%x)\n", cc, intr, arg); + printf("sbdsp_dma_output: cc=%d %p (%p)\n", cc, intr, arg); #endif #ifdef DIAGNOSTIC if (stereo && (cc & 1)) { @@ -1279,33 +1331,39 @@ sbdsp_dma_output(addr, p, cc, intr, arg) if (ISSB16CLASS(sc)) { if (sbdsp16_set_rate(sc, SB_DSP16_OUTPUTRATE, - sc->sc_orate)) + sc->sc_orate)) { + DPRINTF(("sbdsp_dma_output: rate=%d set failed\n", + sc->sc_orate)); goto giveup; + } } else { - if (sbdsp_set_timeconst(sc, sc->sc_otc)) + if (sbdsp_set_timeconst(sc, sc->sc_otc)) { + DPRINTF(("sbdsp_dma_output: tc=%d set failed\n", + sc->sc_orate)); goto giveup; + } } sc->sc_dmadir = SB_DMA_OUT; sc->dmaflags = DMAMODE_WRITE; - if (loop) - sc->dmaflags |= DMAMODE_LOOP; } else { - /* Already started; just return. */ + /* If already started just return. */ if (loop) return 0; } - sc->dmaaddr = p; - sc->dmacnt = loop ? (NBPG/cc)*cc : cc; - sc->dmachan = sc->sc_omodep->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; + if (!loop) { + sc->dmaaddr = p; + sc->dmacnt = cc; + sc->dmachan = sc->sc_omodep->precision == 16 ? sc->sc_drq16 : sc->sc_drq8; #ifdef AUDIO_DEBUG - if (sbdspdebug > 1) - Dprintf("sbdsp_dma_output: dmastart %x %p %d %d\n", - sc->dmaflags, sc->dmaaddr, sc->dmacnt, sc->dmachan); + if (sbdspdebug > 2) + printf("sbdsp: start dma out flags=%x, addr=%p, cnt=%ld, chan=%d\n", + sc->dmaflags, sc->dmaaddr, sc->dmacnt, sc->dmachan); #endif - isa_dmastart(sc->sc_isa, sc->dmachan, sc->dmaaddr, - sc->dmacnt, NULL, sc->dmaflags, BUS_DMA_NOWAIT); + isa_dmastart(sc->sc_isa, sc->dmachan, sc->dmaaddr, + sc->dmacnt, NULL, sc->dmaflags, BUS_DMA_NOWAIT); + } sc->sc_intr = intr; sc->sc_arg = arg; @@ -1361,6 +1419,10 @@ badmode: * (when mode is enabled), completion of dma transmission, or * completion of a dma reception. The three modes are mutually * exclusive so we know a priori which event has occurred. + * + * If there is interrupt sharing or a spurious interrupt occurs + * there is no way to distinuish this on an SB2. So if you have + * an SB2 and experience problems, buy an SB16 (it's only $25). */ int sbdsp_intr(arg) @@ -1372,7 +1434,7 @@ sbdsp_intr(arg) #ifdef AUDIO_DEBUG if (sbdspdebug > 1) - Dprintf("sbdsp_intr: intr=0x%x\n", sc->sc_intr); + printf("sbdsp_intr: intr=%p\n", sc->sc_intr); #endif if (ISSB16CLASS(sc)) { irq = sbdsp_mix_read(sc, SBP_IRQ_STATUS); @@ -1977,3 +2039,34 @@ sbdsp_mixer_query_devinfo(addr, dip) return ENXIO; } + +void * +sb_malloc(addr, size, pool, flags) + void *addr; + unsigned long size; + int pool; + int flags; +{ + struct sbdsp_softc *sc = addr; + + return isa_malloc(sc->sc_isa, 4, size, pool, flags); +} + +void +sb_free(addr, ptr, pool) + void *addr; + void *ptr; + int pool; +{ + isa_free(ptr, pool); +} + +unsigned long +sb_round(addr, size) + void *addr; + unsigned long size; +{ + if (size > MAX_ISADMA) + size = MAX_ISADMA; + return size; +} diff --git a/sys/dev/isa/sbdspvar.h b/sys/dev/isa/sbdspvar.h index 635f40c7d51..cc75224c930 100644 --- a/sys/dev/isa/sbdspvar.h +++ b/sys/dev/isa/sbdspvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: sbdspvar.h,v 1.23 1997/06/06 23:44:04 thorpej Exp $ */ +/* $NetBSD: sbdspvar.h,v 1.24 1997/07/27 01:17:08 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -174,6 +174,8 @@ int sbdsp_get_avail_out_ports __P((void *)); int sbdsp_speaker_ctl __P((void *, int)); int sbdsp_commit_settings __P((void *)); +int sbdsp_dma_init_input __P((void *, void *, int)); +int sbdsp_dma_init_output __P((void *, void *, int)); int sbdsp_dma_output __P((void *, void *, int, void (*)(void *), void*)); int sbdsp_dma_input __P((void *, void *, int, void (*)(void *), void*)); @@ -202,4 +204,9 @@ int sbdsp_mixer_set_port __P((void *, mixer_ctrl_t *)); int sbdsp_mixer_get_port __P((void *, mixer_ctrl_t *)); int sbdsp_mixer_query_devinfo __P((void *, mixer_devinfo_t *)); +void *sb_malloc __P((void *, unsigned long, int, int)); +void sb_free __P((void *, void *, int)); +unsigned long sb_round __P((void *, unsigned long)); + + #endif diff --git a/sys/dev/isa/wss.c b/sys/dev/isa/wss.c index 27932f3d559..b4a69117f06 100644 --- a/sys/dev/isa/wss.c +++ b/sys/dev/isa/wss.c @@ -1,4 +1,4 @@ -/* $NetBSD: wss.c,v 1.26 1997/06/06 23:44:09 thorpej Exp $ */ +/* $NetBSD: wss.c,v 1.27 1997/07/27 01:17:09 augustss Exp $ */ /* * Copyright (c) 1994 John Brezak @@ -171,6 +171,8 @@ struct audio_hw_if wss_hw_if = { wss_set_in_port, wss_get_in_port, ad1848_commit_settings, + ad1848_dma_init_output, + ad1848_dma_init_input, ad1848_dma_output, ad1848_dma_input, ad1848_halt_out_dma, @@ -183,7 +185,10 @@ struct audio_hw_if wss_hw_if = { wss_mixer_set_port, wss_mixer_get_port, wss_query_devinfo, - 0, /* not full-duplex */ + ad1848_malloc, + ad1848_free, + ad1848_round, + AUDIO_PROP_MMAP, 0 }; @@ -224,7 +229,7 @@ wssprobe(parent, match, aux) return 0; } - /* map the ports upto the AD1488 port */ + /* Map the ports upto the AD1848 port */ if (bus_space_map(sc->sc_iot, ia->ia_iobase, WSS_CODEC, 0, &sc->sc_ioh)) return 0; diff --git a/sys/sys/audioio.h b/sys/sys/audioio.h index 0e740403a0f..68e26b9d81f 100644 --- a/sys/sys/audioio.h +++ b/sys/sys/audioio.h @@ -1,4 +1,4 @@ -/* $NetBSD: audioio.h,v 1.11 1997/07/15 07:46:22 augustss Exp $ */ +/* $NetBSD: audioio.h,v 1.12 1997/07/27 01:17:10 augustss Exp $ */ /* * Copyright (c) 1991-1993 Regents of the University of California. @@ -73,7 +73,7 @@ struct audio_info { u_int mode; /* current device mode */ #define AUMODE_PLAY 0x01 #define AUMODE_RECORD 0x02 -#define AUMODE_PLAY_ALL 0x04 /* play all samples--no real-time correction */ +#define AUMODE_PLAY_ALL 0x04 /* don't do real-time correction */ }; typedef struct audio_info audio_info_t; @@ -99,6 +99,12 @@ typedef struct audio_device { char config[MAX_AUDIO_DEV_LEN]; } audio_device_t; +typedef struct audio_offset { + u_int samples; /* Total number of bytes transferred */ + u_int deltablks; /* Blocks transferred since last checked */ + u_int offset; /* Physical transfer offset in buffer */ +} audio_offset_t; + /* * Supported audio encodings */ @@ -140,6 +146,11 @@ typedef struct audio_encoding { #define AUDIO_GETFD _IOR('A', 29, int) #define AUDIO_SETFD _IOWR('A', 30, int) #define AUDIO_PERROR _IOR('A', 31, int) +#define AUDIO_GETIOFFS _IOR('A', 32, struct audio_offset) +#define AUDIO_GETOOFFS _IOR('A', 33, struct audio_offset) +#define AUDIO_GETPROPS _IOR('A', 34, int) +#define AUDIO_PROP_FULLDUPLEX 0x01 +#define AUDIO_PROP_MMAP 0x02 /* * Mixer device |
