summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authoraugustss <augustss@NetBSD.org>1997-07-27 01:16:32 +0000
committeraugustss <augustss@NetBSD.org>1997-07-27 01:16:32 +0000
commit9745684ebe151a825bdef45d38da2ef82fc893d1 (patch)
tree9fc1a39eeab95505d742a8f6fe2003dc0381e354 /sys
parent3ca46d33e107a26b997c048032ddeacf5270b46f (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')
-rw-r--r--sys/arch/arm32/mainbus/lmcaudio.c9
-rw-r--r--sys/arch/arm32/mainbus/vidcaudio.c9
-rw-r--r--sys/arch/arm32/vidc/lmcaudio.c9
-rw-r--r--sys/arch/arm32/vidc/vidcaudio.c9
-rw-r--r--sys/arch/sparc/dev/am7930_sparc.c9
-rw-r--r--sys/arch/sparc/dev/amd7930.c9
-rw-r--r--sys/compat/linux/common/linux_break.c4
-rw-r--r--sys/compat/linux/common/linux_misc.c4
-rw-r--r--sys/compat/linux/common/linux_misc_notalpha.c4
-rw-r--r--sys/compat/linux/common/linux_oldmmap.c4
-rw-r--r--sys/compat/linux/common/linux_oldolduname.c4
-rw-r--r--sys/compat/linux/common/linux_oldselect.c4
-rw-r--r--sys/compat/linux/common/linux_olduname.c4
-rw-r--r--sys/compat/linux/common/linux_pipe.c4
-rw-r--r--sys/compat/linux/linux_misc.c4
-rw-r--r--sys/compat/linux/multiarch/linux_break.c4
-rw-r--r--sys/compat/linux/multiarch/linux_misc_notalpha.c4
-rw-r--r--sys/compat/linux/multiarch/linux_oldmmap.c4
-rw-r--r--sys/compat/linux/multiarch/linux_oldolduname.c4
-rw-r--r--sys/compat/linux/multiarch/linux_oldselect.c4
-rw-r--r--sys/compat/linux/multiarch/linux_olduname.c4
-rw-r--r--sys/compat/linux/multiarch/linux_pipe.c4
-rw-r--r--sys/compat/ossaudio/ossaudio.c75
-rw-r--r--sys/compat/ossaudio/ossaudiovar.h28
-rw-r--r--sys/dev/audio.c1417
-rw-r--r--sys/dev/audio_if.h11
-rw-r--r--sys/dev/audiovar.h100
-rw-r--r--sys/dev/ic/am7930.c9
-rw-r--r--sys/dev/isa/ad1848.c212
-rw-r--r--sys/dev/isa/ad1848var.h15
-rw-r--r--sys/dev/isa/gus.c40
-rw-r--r--sys/dev/isa/isadma.c71
-rw-r--r--sys/dev/isa/isadmavar.h8
-rw-r--r--sys/dev/isa/pas.c9
-rw-r--r--sys/dev/isa/pss.c16
-rw-r--r--sys/dev/isa/sb.c9
-rw-r--r--sys/dev/isa/sb_isa.c4
-rw-r--r--sys/dev/isa/sbdsp.c181
-rw-r--r--sys/dev/isa/sbdspvar.h9
-rw-r--r--sys/dev/isa/wss.c11
-rw-r--r--sys/sys/audioio.h15
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