MFC nearly everything of the soundsystem except recent commits and
most of the sysctl's (those which would introduce a new interface). The spdif_enabled sysctl is still there (or more correctly: added to another driver). A rough overview what's there now: - new driver for ATI chips (snd_atiixp) - support for some Intel HDA chips in AC97 mode (no real HDA support!), this doesn't work with every mainboard and is subject to the wiring on the mainboard (no servicable parts inside) - MPSAFE and fixes for snd_als4000(4), snd_es137x(4), snd_via82c686(4), snd_via8233(4) and snd_ich(4) - 24bit and 32bit sound format support - feeder infrastructure (format, rate) has been reworked, new feeder (volume) has been introduced - lots of LOR and panic issues fixed - and a lot of small or not so small fixes I may have forgotten... As noted in UPDATING: you may want to recompile mplayer (after booting into the new world) to get all new features. Tested by: a lot of people Requested by: ariff Submitted by: ariff
This commit is contained in:
parent
30ca7bc8d2
commit
6020e1d27b
5
UPDATING
5
UPDATING
@ -8,6 +8,11 @@ Items affecting the ports and packages system can be found in
|
|||||||
/usr/ports/UPDATING. Please read that file before running
|
/usr/ports/UPDATING. Please read that file before running
|
||||||
portupgrade.
|
portupgrade.
|
||||||
|
|
||||||
|
20051230:
|
||||||
|
A lot of fixes and new features in the soundsystem. To get all
|
||||||
|
benefits, you may want to recompile mplayer (if installed) after
|
||||||
|
booting the new world.
|
||||||
|
|
||||||
20051222:
|
20051222:
|
||||||
Bug fixes to the trimdomain(3) function in libutil may result in
|
Bug fixes to the trimdomain(3) function in libutil may result in
|
||||||
slight changes to the host names appearing in log files under
|
slight changes to the host names appearing in log files under
|
||||||
|
@ -278,6 +278,7 @@ MAN= aac.4 \
|
|||||||
sn.4 \
|
sn.4 \
|
||||||
snd_ad1816.4 \
|
snd_ad1816.4 \
|
||||||
snd_als4000.4 \
|
snd_als4000.4 \
|
||||||
|
snd_atiixp.4 \
|
||||||
snd_cmi.4 \
|
snd_cmi.4 \
|
||||||
snd_cs4281.4 \
|
snd_cs4281.4 \
|
||||||
snd_csa.4 \
|
snd_csa.4 \
|
||||||
|
@ -24,21 +24,45 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd August 18, 2005
|
.Dd December 15, 2005
|
||||||
.Dt SND_ES137X 4
|
.Dt SND_ES137X 4
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm snd_es137x
|
.Nm snd_es137x
|
||||||
.Nd "Ensoniq AudioPCI ES137x bridge device driver"
|
.Nd "Ensoniq AudioPCI ES137x bridge device driver"
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
|
To compile this driver into the kernel, place the following lines in your
|
||||||
|
kernel configuration file:
|
||||||
|
.Bd -ragged -offset indent
|
||||||
.Cd "device sound"
|
.Cd "device sound"
|
||||||
.Cd "device snd_es137x"
|
.Cd "device snd_es137x"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Alternatively, to load the driver as a module at boot time, place the
|
||||||
|
following line in
|
||||||
|
.Xr loader.conf 5 :
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
snd_es137x_load="YES"
|
||||||
|
.Ed
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
bridge driver allows the generic audio driver
|
bridge driver allows the generic audio driver
|
||||||
.Xr sound 4
|
.Xr sound 4
|
||||||
to attach to the Ensoniq 137x audio cards.
|
to attach to the Ensoniq 137x audio cards.
|
||||||
|
.Ss Runtime Configuration
|
||||||
|
The following
|
||||||
|
.Xr sysctl 8
|
||||||
|
variable are available in addition to those available to all
|
||||||
|
.Xr sound 4
|
||||||
|
devices:
|
||||||
|
.Bl -tag -width ".Va hw.snd.pcm%d.spdif_enabled" -offset indent
|
||||||
|
.It Va hw.snd.pcm%d.spdif_enabled
|
||||||
|
Enables S/PDIF output on the primary playback channel.
|
||||||
|
This
|
||||||
|
.Xr sysctl 8
|
||||||
|
variable is available only if the device is known to support S/PDIF output.
|
||||||
|
.El
|
||||||
.Sh HARDWARE
|
.Sh HARDWARE
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
@ -73,9 +97,10 @@ Ensoniq AudioPCI ES1373-8
|
|||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
manual page first appeared in
|
device driver first appeared in
|
||||||
.Fx 5.3 .
|
.Fx 4.0 .
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
.An "Russell Cattelan" Aq cattelan@thebarn.com
|
.An "Russell Cattelan" Aq cattelan@thebarn.com
|
||||||
.An "Cameron Grant" Aq cg@FreeBSD.org
|
.An "Cameron Grant" Aq cg@FreeBSD.org
|
||||||
.An "Joachim Kuebart"
|
.An "Joachim Kuebart"
|
||||||
|
.An "Jonathan Noack" Aq noackjr@alumni.rice.edu
|
||||||
|
@ -24,15 +24,26 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd March 2, 2005
|
.Dd December 1, 2005
|
||||||
.Dt SND_VIA8233 4
|
.Dt SND_VIA8233 4
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm snd_via8233
|
.Nm snd_via8233
|
||||||
.Nd "VIA Technologies VT8233 bridge device driver"
|
.Nd "VIA Technologies VT8233 bridge device driver"
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
|
To compile this driver into the kernel, place the following lines in your
|
||||||
|
kernel configuration file:
|
||||||
|
.Bd -ragged -offset indent
|
||||||
.Cd "device sound"
|
.Cd "device sound"
|
||||||
.Cd "device snd_via8233"
|
.Cd "device snd_via8233"
|
||||||
|
.Ed
|
||||||
|
.Pp
|
||||||
|
Alternatively, to load the driver as a module at boot time, place the
|
||||||
|
following line in
|
||||||
|
.Xr loader.conf 5 :
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
snd_via8233_load="YES"
|
||||||
|
.Ed
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
@ -65,6 +76,9 @@ The
|
|||||||
.Nm
|
.Nm
|
||||||
device driver first appeared in
|
device driver first appeared in
|
||||||
.Fx 4.7 .
|
.Fx 4.7 .
|
||||||
|
.Sh AUTHORS
|
||||||
|
This manual page was written by
|
||||||
|
.An Joel Dahl Aq joel@FreeBSD.org .
|
||||||
.Sh BUGS
|
.Sh BUGS
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
|
@ -274,6 +274,7 @@ ng_vlan_load="NO" # IEEE 802.1Q VLAN tagging netgraph node type
|
|||||||
sound_load="NO" # Digital sound subsystem
|
sound_load="NO" # Digital sound subsystem
|
||||||
snd_ad1816_load="NO" # ad1816
|
snd_ad1816_load="NO" # ad1816
|
||||||
snd_als4000_load="NO" # als4000
|
snd_als4000_load="NO" # als4000
|
||||||
|
snd_atiixp_load="NO" # atiixp
|
||||||
snd_cmi_load="NO" # cmi
|
snd_cmi_load="NO" # cmi
|
||||||
snd_cs4281_load="NO" # cs4281
|
snd_cs4281_load="NO" # cs4281
|
||||||
snd_csa_load="NO" # csa
|
snd_csa_load="NO" # csa
|
||||||
|
@ -1926,6 +1926,7 @@ device sound
|
|||||||
# since this is unsupported at the moment...).
|
# since this is unsupported at the moment...).
|
||||||
#
|
#
|
||||||
# snd_als4000: Avance Logic ALS4000 PCI.
|
# snd_als4000: Avance Logic ALS4000 PCI.
|
||||||
|
# snd_atiixp: ATI IXP 200/300/400 PCI.
|
||||||
# snd_ad1816: Analog Devices AD1816 ISA PnP/non-PnP.
|
# snd_ad1816: Analog Devices AD1816 ISA PnP/non-PnP.
|
||||||
# snd_audiocs: Crystal Semiconductor CS4231 SBus/EBus.
|
# snd_audiocs: Crystal Semiconductor CS4231 SBus/EBus.
|
||||||
# snd_cmi: CMedia CMI8338/CMI8738 PCI.
|
# snd_cmi: CMedia CMI8338/CMI8738 PCI.
|
||||||
@ -1961,6 +1962,7 @@ device sound
|
|||||||
|
|
||||||
device snd_ad1816
|
device snd_ad1816
|
||||||
device snd_als4000
|
device snd_als4000
|
||||||
|
device snd_atiixp
|
||||||
#device snd_au88x0
|
#device snd_au88x0
|
||||||
#device snd_audiocs
|
#device snd_audiocs
|
||||||
device snd_cmi
|
device snd_cmi
|
||||||
|
@ -798,6 +798,7 @@ dev/sound/isa/sb8.c optional snd_sb8 isa
|
|||||||
dev/sound/isa/sbc.c optional snd_sbc isa
|
dev/sound/isa/sbc.c optional snd_sbc isa
|
||||||
dev/sound/isa/sndbuf_dma.c optional sound isa
|
dev/sound/isa/sndbuf_dma.c optional sound isa
|
||||||
dev/sound/pci/als4000.c optional snd_als4000 pci
|
dev/sound/pci/als4000.c optional snd_als4000 pci
|
||||||
|
dev/sound/pci/atiixp.c optional snd_atiixp.c pci
|
||||||
#dev/sound/pci/au88x0.c optional snd_au88x0 pci
|
#dev/sound/pci/au88x0.c optional snd_au88x0 pci
|
||||||
dev/sound/pci/cmi.c optional snd_cmi pci
|
dev/sound/pci/cmi.c optional snd_cmi pci
|
||||||
dev/sound/pci/cs4281.c optional snd_cs4281 pci
|
dev/sound/pci/cs4281.c optional snd_cs4281 pci
|
||||||
@ -830,6 +831,7 @@ dev/sound/pcm/feeder.c optional sound
|
|||||||
dev/sound/pcm/feeder_fmt.c optional sound
|
dev/sound/pcm/feeder_fmt.c optional sound
|
||||||
dev/sound/pcm/feeder_if.m optional sound
|
dev/sound/pcm/feeder_if.m optional sound
|
||||||
dev/sound/pcm/feeder_rate.c optional sound
|
dev/sound/pcm/feeder_rate.c optional sound
|
||||||
|
dev/sound/pcm/feeder_volume.c optional sound
|
||||||
dev/sound/pcm/mixer.c optional sound
|
dev/sound/pcm/mixer.c optional sound
|
||||||
dev/sound/pcm/mixer_if.m optional sound
|
dev/sound/pcm/mixer_if.m optional sound
|
||||||
dev/sound/pcm/sndstat.c optional sound
|
dev/sound/pcm/sndstat.c optional sound
|
||||||
|
@ -54,6 +54,7 @@ MODULE_VERSION(snd_driver, 1);
|
|||||||
|
|
||||||
MODULE_DEPEND(snd_driver, snd_ad1816, 1, 1, 1);
|
MODULE_DEPEND(snd_driver, snd_ad1816, 1, 1, 1);
|
||||||
MODULE_DEPEND(snd_driver, snd_als4000, 1, 1, 1);
|
MODULE_DEPEND(snd_driver, snd_als4000, 1, 1, 1);
|
||||||
|
MODULE_DEPEND(snd_driver, snd_atiixp, 1, 1, 1);
|
||||||
/* MODULE_DEPEND(snd_driver, snd_aureal, 1, 1, 1); */
|
/* MODULE_DEPEND(snd_driver, snd_aureal, 1, 1, 1); */
|
||||||
MODULE_DEPEND(snd_driver, snd_cmi, 1, 1, 1);
|
MODULE_DEPEND(snd_driver, snd_cmi, 1, 1, 1);
|
||||||
MODULE_DEPEND(snd_driver, snd_cs4281, 1, 1, 1);
|
MODULE_DEPEND(snd_driver, snd_cs4281, 1, 1, 1);
|
||||||
|
@ -138,12 +138,16 @@ ad1816_intr(void *arg)
|
|||||||
}
|
}
|
||||||
/* check for capture interupt */
|
/* check for capture interupt */
|
||||||
if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) {
|
if (sndbuf_runsz(ad1816->rch.buffer) && (c & AD1816_INTRCI)) {
|
||||||
|
ad1816_unlock(ad1816);
|
||||||
chn_intr(ad1816->rch.channel);
|
chn_intr(ad1816->rch.channel);
|
||||||
|
ad1816_lock(ad1816);
|
||||||
served |= AD1816_INTRCI; /* cp served */
|
served |= AD1816_INTRCI; /* cp served */
|
||||||
}
|
}
|
||||||
/* check for playback interupt */
|
/* check for playback interupt */
|
||||||
if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) {
|
if (sndbuf_runsz(ad1816->pch.buffer) && (c & AD1816_INTRPI)) {
|
||||||
|
ad1816_unlock(ad1816);
|
||||||
chn_intr(ad1816->pch.channel);
|
chn_intr(ad1816->pch.channel);
|
||||||
|
ad1816_lock(ad1816);
|
||||||
served |= AD1816_INTRPI; /* pb served */
|
served |= AD1816_INTRPI; /* pb served */
|
||||||
}
|
}
|
||||||
if (served == 0) {
|
if (served == 0) {
|
||||||
|
@ -361,8 +361,11 @@ ess_intr(void *arg)
|
|||||||
rirq = (src & sc->rch.hwch)? 1 : 0;
|
rirq = (src & sc->rch.hwch)? 1 : 0;
|
||||||
|
|
||||||
if (pirq) {
|
if (pirq) {
|
||||||
if (sc->pch.run)
|
if (sc->pch.run) {
|
||||||
|
ess_unlock(sc);
|
||||||
chn_intr(sc->pch.channel);
|
chn_intr(sc->pch.channel);
|
||||||
|
ess_lock(sc);
|
||||||
|
}
|
||||||
if (sc->pch.stopping) {
|
if (sc->pch.stopping) {
|
||||||
sc->pch.run = 0;
|
sc->pch.run = 0;
|
||||||
sndbuf_dma(sc->pch.buffer, PCMTRIG_STOP);
|
sndbuf_dma(sc->pch.buffer, PCMTRIG_STOP);
|
||||||
@ -375,8 +378,11 @@ ess_intr(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rirq) {
|
if (rirq) {
|
||||||
if (sc->rch.run)
|
if (sc->rch.run) {
|
||||||
|
ess_unlock(sc);
|
||||||
chn_intr(sc->rch.channel);
|
chn_intr(sc->rch.channel);
|
||||||
|
ess_lock(sc);
|
||||||
|
}
|
||||||
if (sc->rch.stopping) {
|
if (sc->rch.stopping) {
|
||||||
sc->rch.run = 0;
|
sc->rch.run = 0;
|
||||||
sndbuf_dma(sc->rch.buffer, PCMTRIG_STOP);
|
sndbuf_dma(sc->rch.buffer, PCMTRIG_STOP);
|
||||||
|
@ -92,7 +92,9 @@ static driver_intr_t mss_intr;
|
|||||||
|
|
||||||
/* prototypes for local functions */
|
/* prototypes for local functions */
|
||||||
static int mss_detect(device_t dev, struct mss_info *mss);
|
static int mss_detect(device_t dev, struct mss_info *mss);
|
||||||
|
#ifndef PC98
|
||||||
static int opti_detect(device_t dev, struct mss_info *mss);
|
static int opti_detect(device_t dev, struct mss_info *mss);
|
||||||
|
#endif
|
||||||
static char *ymf_test(device_t dev, struct mss_info *mss);
|
static char *ymf_test(device_t dev, struct mss_info *mss);
|
||||||
static void ad_unmute(struct mss_info *mss);
|
static void ad_unmute(struct mss_info *mss);
|
||||||
|
|
||||||
@ -111,7 +113,9 @@ static void ad_leave_MCE(struct mss_info *mss);
|
|||||||
/* OPTi-specific functions */
|
/* OPTi-specific functions */
|
||||||
static void opti_write(struct mss_info *mss, u_char reg,
|
static void opti_write(struct mss_info *mss, u_char reg,
|
||||||
u_char data);
|
u_char data);
|
||||||
|
#ifndef PC98
|
||||||
static u_char opti_read(struct mss_info *mss, u_char reg);
|
static u_char opti_read(struct mss_info *mss, u_char reg);
|
||||||
|
#endif
|
||||||
static int opti_init(device_t dev, struct mss_info *mss);
|
static int opti_init(device_t dev, struct mss_info *mss);
|
||||||
|
|
||||||
/* io primitives */
|
/* io primitives */
|
||||||
@ -795,11 +799,15 @@ mss_intr(void *arg)
|
|||||||
c &= ~served;
|
c &= ~served;
|
||||||
if (sndbuf_runsz(mss->pch.buffer) && (c & 0x10)) {
|
if (sndbuf_runsz(mss->pch.buffer) && (c & 0x10)) {
|
||||||
served |= 0x10;
|
served |= 0x10;
|
||||||
|
mss_unlock(mss);
|
||||||
chn_intr(mss->pch.channel);
|
chn_intr(mss->pch.channel);
|
||||||
|
mss_lock(mss);
|
||||||
}
|
}
|
||||||
if (sndbuf_runsz(mss->rch.buffer) && (c & 0x20)) {
|
if (sndbuf_runsz(mss->rch.buffer) && (c & 0x20)) {
|
||||||
served |= 0x20;
|
served |= 0x20;
|
||||||
|
mss_unlock(mss);
|
||||||
chn_intr(mss->rch.channel);
|
chn_intr(mss->rch.channel);
|
||||||
|
mss_lock(mss);
|
||||||
}
|
}
|
||||||
/* now ack the interrupt */
|
/* now ack the interrupt */
|
||||||
if (FULL_DUPLEX(mss)) ad_write(mss, 24, ~c); /* ack selectively */
|
if (FULL_DUPLEX(mss)) ad_write(mss, 24, ~c); /* ack selectively */
|
||||||
@ -970,6 +978,7 @@ mss_speed(struct mss_chinfo *ch, int speed)
|
|||||||
abs(speed-speeds[i]) < abs(speed-speeds[sel])) sel = i;
|
abs(speed-speeds[i]) < abs(speed-speeds[sel])) sel = i;
|
||||||
speed = speeds[sel];
|
speed = speeds[sel];
|
||||||
ad_write(mss, 8, (ad_read(mss, 8) & 0xf0) | sel);
|
ad_write(mss, 8, (ad_read(mss, 8) & 0xf0) | sel);
|
||||||
|
ad_wait_init(mss, 10000);
|
||||||
}
|
}
|
||||||
ad_leave_MCE(mss);
|
ad_leave_MCE(mss);
|
||||||
|
|
||||||
@ -1009,7 +1018,11 @@ mss_format(struct mss_chinfo *ch, u_int32_t format)
|
|||||||
arg <<= 4;
|
arg <<= 4;
|
||||||
ad_enter_MCE(mss);
|
ad_enter_MCE(mss);
|
||||||
ad_write(mss, 8, (ad_read(mss, 8) & 0x0f) | arg);
|
ad_write(mss, 8, (ad_read(mss, 8) & 0x0f) | arg);
|
||||||
if (FULL_DUPLEX(mss)) ad_write(mss, 28, arg); /* capture mode */
|
ad_wait_init(mss, 10000);
|
||||||
|
if (ad_read(mss, 12) & 0x40) { /* mode2? */
|
||||||
|
ad_write(mss, 28, arg); /* capture mode */
|
||||||
|
ad_wait_init(mss, 10000);
|
||||||
|
}
|
||||||
ad_leave_MCE(mss);
|
ad_leave_MCE(mss);
|
||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
@ -1111,8 +1124,16 @@ opti931_intr(void *arg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sndbuf_runsz(mss->rch.buffer) && (mc11 & 8)) chn_intr(mss->rch.channel);
|
if (sndbuf_runsz(mss->rch.buffer) && (mc11 & 8)) {
|
||||||
if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) chn_intr(mss->pch.channel);
|
mss_unlock(mss);
|
||||||
|
chn_intr(mss->rch.channel);
|
||||||
|
mss_lock(mss);
|
||||||
|
}
|
||||||
|
if (sndbuf_runsz(mss->pch.buffer) && (mc11 & 4)) {
|
||||||
|
mss_unlock(mss);
|
||||||
|
chn_intr(mss->pch.channel);
|
||||||
|
mss_lock(mss);
|
||||||
|
}
|
||||||
opti_wr(mss, 11, ~mc11); /* ack */
|
opti_wr(mss, 11, ~mc11); /* ack */
|
||||||
if (--loops) goto again;
|
if (--loops) goto again;
|
||||||
mss_unlock(mss);
|
mss_unlock(mss);
|
||||||
@ -1355,6 +1376,7 @@ mss_detect(device_t dev, struct mss_info *mss)
|
|||||||
name = "AD1848";
|
name = "AD1848";
|
||||||
mss->bd_id = MD_AD1848; /* AD1848 or CS4248 */
|
mss->bd_id = MD_AD1848; /* AD1848 or CS4248 */
|
||||||
|
|
||||||
|
#ifndef PC98
|
||||||
if (opti_detect(dev, mss)) {
|
if (opti_detect(dev, mss)) {
|
||||||
switch (mss->bd_id) {
|
switch (mss->bd_id) {
|
||||||
case MD_OPTI924:
|
case MD_OPTI924:
|
||||||
@ -1367,6 +1389,7 @@ mss_detect(device_t dev, struct mss_info *mss)
|
|||||||
printf("Found OPTi device %s\n", name);
|
printf("Found OPTi device %s\n", name);
|
||||||
if (opti_init(dev, mss) == 0) goto gotit;
|
if (opti_init(dev, mss) == 0) goto gotit;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that the I/O address is in use.
|
* Check that the I/O address is in use.
|
||||||
@ -1573,6 +1596,7 @@ mss_detect(device_t dev, struct mss_info *mss)
|
|||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef PC98
|
||||||
static int
|
static int
|
||||||
opti_detect(device_t dev, struct mss_info *mss)
|
opti_detect(device_t dev, struct mss_info *mss)
|
||||||
{
|
{
|
||||||
@ -1618,6 +1642,7 @@ opti_detect(device_t dev, struct mss_info *mss)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
ymf_test(device_t dev, struct mss_info *mss)
|
ymf_test(device_t dev, struct mss_info *mss)
|
||||||
@ -2152,6 +2177,7 @@ opti_write(struct mss_info *mss, u_char reg, u_char val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef PC98
|
||||||
u_char
|
u_char
|
||||||
opti_read(struct mss_info *mss, u_char reg)
|
opti_read(struct mss_info *mss, u_char reg)
|
||||||
{
|
{
|
||||||
@ -2175,6 +2201,7 @@ opti_read(struct mss_info *mss, u_char reg)
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static device_method_t pnpmss_methods[] = {
|
static device_method_t pnpmss_methods[] = {
|
||||||
/* Device interface */
|
/* Device interface */
|
||||||
|
@ -370,23 +370,32 @@ static int
|
|||||||
sb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
|
sb16mix_setrecsrc(struct snd_mixer *m, u_int32_t src)
|
||||||
{
|
{
|
||||||
struct sb_info *sb = mix_getdevinfo(m);
|
struct sb_info *sb = mix_getdevinfo(m);
|
||||||
u_char recdev;
|
u_char recdev_l, recdev_r;
|
||||||
|
|
||||||
recdev = 0;
|
recdev_l = 0;
|
||||||
if (src & SOUND_MASK_MIC)
|
recdev_r = 0;
|
||||||
recdev |= 0x01; /* mono mic */
|
if (src & SOUND_MASK_MIC) {
|
||||||
|
recdev_l |= 0x01; /* mono mic */
|
||||||
|
recdev_r |= 0x01;
|
||||||
|
}
|
||||||
|
|
||||||
if (src & SOUND_MASK_CD)
|
if (src & SOUND_MASK_CD) {
|
||||||
recdev |= 0x06; /* l+r cd */
|
recdev_l |= 0x04; /* l cd */
|
||||||
|
recdev_r |= 0x02; /* r cd */
|
||||||
|
}
|
||||||
|
|
||||||
if (src & SOUND_MASK_LINE)
|
if (src & SOUND_MASK_LINE) {
|
||||||
recdev |= 0x18; /* l+r line */
|
recdev_l |= 0x10; /* l line */
|
||||||
|
recdev_r |= 0x08; /* r line */
|
||||||
|
}
|
||||||
|
|
||||||
if (src & SOUND_MASK_SYNTH)
|
if (src & SOUND_MASK_SYNTH) {
|
||||||
recdev |= 0x60; /* l+r midi */
|
recdev_l |= 0x40; /* l midi */
|
||||||
|
recdev_r |= 0x20; /* r midi */
|
||||||
|
}
|
||||||
|
|
||||||
sb_setmixer(sb, SB16_IMASK_L, recdev);
|
sb_setmixer(sb, SB16_IMASK_L, recdev_l);
|
||||||
sb_setmixer(sb, SB16_IMASK_R, recdev);
|
sb_setmixer(sb, SB16_IMASK_R, recdev_r);
|
||||||
|
|
||||||
/* Switch on/off FM tuner source */
|
/* Switch on/off FM tuner source */
|
||||||
if (src & SOUND_MASK_LINE1)
|
if (src & SOUND_MASK_LINE1)
|
||||||
@ -494,7 +503,7 @@ static void
|
|||||||
sb_intr(void *arg)
|
sb_intr(void *arg)
|
||||||
{
|
{
|
||||||
struct sb_info *sb = (struct sb_info *)arg;
|
struct sb_info *sb = (struct sb_info *)arg;
|
||||||
int reason = 3, c;
|
int reason, c;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
* The Vibra16X has separate flags for 8 and 16 bit transfers, but
|
||||||
@ -570,8 +579,9 @@ sb_setup(struct sb_info *sb)
|
|||||||
sb_reset_dsp(sb);
|
sb_reset_dsp(sb);
|
||||||
|
|
||||||
if (sb->bd_flags & BD_F_SB16X) {
|
if (sb->bd_flags & BD_F_SB16X) {
|
||||||
|
/* full-duplex doesn't work! */
|
||||||
pprio = sb->pch.run? 1 : 0;
|
pprio = sb->pch.run? 1 : 0;
|
||||||
sndbuf_dmasetup(sb->pch.buffer, pprio? sb->drq1 : NULL);
|
sndbuf_dmasetup(sb->pch.buffer, pprio? sb->drq1 : sb->drq2);
|
||||||
sb->pch.dch = pprio? 1 : 0;
|
sb->pch.dch = pprio? 1 : 0;
|
||||||
sndbuf_dmasetup(sb->rch.buffer, pprio? sb->drq2 : sb->drq1);
|
sndbuf_dmasetup(sb->rch.buffer, pprio? sb->drq2 : sb->drq1);
|
||||||
sb->rch.dch = pprio? 2 : 1;
|
sb->rch.dch = pprio? 2 : 1;
|
||||||
@ -848,7 +858,7 @@ sb16_attach(device_t dev)
|
|||||||
else
|
else
|
||||||
status2[0] = '\0';
|
status2[0] = '\0';
|
||||||
|
|
||||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %ud %s",
|
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld drq %ld%s bufsz %u %s",
|
||||||
rman_get_start(sb->io_base), rman_get_start(sb->irq),
|
rman_get_start(sb->io_base), rman_get_start(sb->irq),
|
||||||
rman_get_start(sb->drq1), status2, sb->bufsize,
|
rman_get_start(sb->drq1), status2, sb->bufsize,
|
||||||
PCM_KLDSTRING(snd_sb16));
|
PCM_KLDSTRING(snd_sb16));
|
||||||
|
@ -475,11 +475,17 @@ sb_intr(void *arg)
|
|||||||
struct sb_info *sb = (struct sb_info *)arg;
|
struct sb_info *sb = (struct sb_info *)arg;
|
||||||
|
|
||||||
sb_lock(sb);
|
sb_lock(sb);
|
||||||
if (sndbuf_runsz(sb->pch.buffer) > 0)
|
if (sndbuf_runsz(sb->pch.buffer) > 0) {
|
||||||
|
sb_unlock(sb);
|
||||||
chn_intr(sb->pch.channel);
|
chn_intr(sb->pch.channel);
|
||||||
|
sb_lock(sb);
|
||||||
|
}
|
||||||
|
|
||||||
if (sndbuf_runsz(sb->rch.buffer) > 0)
|
if (sndbuf_runsz(sb->rch.buffer) > 0) {
|
||||||
|
sb_unlock(sb);
|
||||||
chn_intr(sb->rch.channel);
|
chn_intr(sb->rch.channel);
|
||||||
|
sb_lock(sb);
|
||||||
|
}
|
||||||
|
|
||||||
sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
|
sb_rd(sb, DSP_DATA_AVAIL); /* int ack */
|
||||||
sb_unlock(sb);
|
sb_unlock(sb);
|
||||||
@ -564,8 +570,16 @@ sb_stop(struct sb_chinfo *ch)
|
|||||||
sb_lock(sb);
|
sb_lock(sb);
|
||||||
if (sb->bd_flags & BD_F_HISPEED)
|
if (sb->bd_flags & BD_F_HISPEED)
|
||||||
sb_reset_dsp(sb);
|
sb_reset_dsp(sb);
|
||||||
else
|
else {
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* NOTE: DSP_CMD_DMAEXIT_8 does not work with old
|
||||||
|
* soundblaster.
|
||||||
|
*/
|
||||||
sb_cmd(sb, DSP_CMD_DMAEXIT_8);
|
sb_cmd(sb, DSP_CMD_DMAEXIT_8);
|
||||||
|
#endif
|
||||||
|
sb_reset_dsp(sb);
|
||||||
|
}
|
||||||
|
|
||||||
if (play)
|
if (play)
|
||||||
sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
|
sb_cmd(sb, DSP_CMD_SPKOFF); /* speaker off */
|
||||||
|
@ -259,6 +259,7 @@ static struct isa_pnp_id sbc_ids[] = {
|
|||||||
|
|
||||||
{0x81167316, "ESS ES1681"}, /* ESS1681 */
|
{0x81167316, "ESS ES1681"}, /* ESS1681 */
|
||||||
{0x02017316, "ESS ES1688"}, /* ESS1688 */
|
{0x02017316, "ESS ES1688"}, /* ESS1688 */
|
||||||
|
{0x68097316, "ESS ES1688"}, /* ESS1688 */
|
||||||
{0x68187316, "ESS ES1868"}, /* ESS1868 */
|
{0x68187316, "ESS ES1868"}, /* ESS1868 */
|
||||||
{0x03007316, "ESS ES1869"}, /* ESS1869 */
|
{0x03007316, "ESS ES1869"}, /* ESS1869 */
|
||||||
{0x69187316, "ESS ES1869"}, /* ESS1869 */
|
{0x69187316, "ESS ES1869"}, /* ESS1869 */
|
||||||
|
@ -75,6 +75,7 @@ struct sc_info {
|
|||||||
struct resource *reg, *irq;
|
struct resource *reg, *irq;
|
||||||
int regid, irqid;
|
int regid, irqid;
|
||||||
void *ih;
|
void *ih;
|
||||||
|
struct mtx *lock;
|
||||||
|
|
||||||
unsigned int bufsz;
|
unsigned int bufsz;
|
||||||
struct sc_chinfo pch, rch;
|
struct sc_chinfo pch, rch;
|
||||||
@ -90,7 +91,11 @@ static u_int32_t als_format[] = {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct pcmchan_caps als_caps = { 4000, 48000, als_format, 0 };
|
/*
|
||||||
|
* I don't believe this rotten soundcard can do 48k, really,
|
||||||
|
* trust me.
|
||||||
|
*/
|
||||||
|
static struct pcmchan_caps als_caps = { 4000, 44100, als_format, 0 };
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Register Utilities */
|
/* Register Utilities */
|
||||||
@ -199,6 +204,7 @@ alschan_init(kobj_t obj, void *devinfo,
|
|||||||
struct sc_info *sc = devinfo;
|
struct sc_info *sc = devinfo;
|
||||||
struct sc_chinfo *ch;
|
struct sc_chinfo *ch;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
if (dir == PCMDIR_PLAY) {
|
if (dir == PCMDIR_PLAY) {
|
||||||
ch = &sc->pch;
|
ch = &sc->pch;
|
||||||
ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS;
|
ch->gcr_fifo_status = ALS_GCR_FIFO0_STATUS;
|
||||||
@ -213,9 +219,11 @@ alschan_init(kobj_t obj, void *devinfo,
|
|||||||
ch->format = AFMT_U8;
|
ch->format = AFMT_U8;
|
||||||
ch->speed = DSP_DEFAULT_SPEED;
|
ch->speed = DSP_DEFAULT_SPEED;
|
||||||
ch->buffer = b;
|
ch->buffer = b;
|
||||||
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0) {
|
snd_mtxunlock(sc->lock);
|
||||||
|
|
||||||
|
if (sndbuf_alloc(ch->buffer, sc->parent_dmat, sc->bufsz) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,9 +271,12 @@ static int
|
|||||||
alschan_getptr(kobj_t obj, void *data)
|
alschan_getptr(kobj_t obj, void *data)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
int32_t pos, sz;
|
int32_t pos, sz;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff;
|
pos = als_gcr_rd(ch->parent, ch->gcr_fifo_status) & 0xffff;
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
sz = sndbuf_getsize(ch->buffer);
|
sz = sndbuf_getsize(ch->buffer);
|
||||||
return (2 * sz - pos - 1) % sz;
|
return (2 * sz - pos - 1) % sz;
|
||||||
}
|
}
|
||||||
@ -378,7 +389,9 @@ static int
|
|||||||
alspchan_trigger(kobj_t obj, void *data, int go)
|
alspchan_trigger(kobj_t obj, void *data, int go)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
switch(go) {
|
switch(go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
als_playback_start(ch);
|
als_playback_start(ch);
|
||||||
@ -387,6 +400,7 @@ alspchan_trigger(kobj_t obj, void *data, int go)
|
|||||||
als_playback_stop(ch);
|
als_playback_stop(ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,7 +482,9 @@ static int
|
|||||||
alsrchan_trigger(kobj_t obj, void *data, int go)
|
alsrchan_trigger(kobj_t obj, void *data, int go)
|
||||||
{
|
{
|
||||||
struct sc_chinfo *ch = data;
|
struct sc_chinfo *ch = data;
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
switch(go) {
|
switch(go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
als_capture_start(ch);
|
als_capture_start(ch);
|
||||||
@ -477,6 +493,7 @@ alsrchan_trigger(kobj_t obj, void *data, int go)
|
|||||||
als_capture_stop(ch);
|
als_capture_stop(ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,8 +595,13 @@ alsmix_setrecsrc(struct snd_mixer *m, u_int32_t src)
|
|||||||
|
|
||||||
for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
for (i = l = r = 0; i < SOUND_MIXER_NRDEVICES; i++) {
|
||||||
if (src & (1 << i)) {
|
if (src & (1 << i)) {
|
||||||
|
if (amt[i].iselect == 1) { /* microphone */
|
||||||
l |= amt[i].iselect;
|
l |= amt[i].iselect;
|
||||||
r |= amt[i].iselect << 1;
|
r |= amt[i].iselect;
|
||||||
|
} else {
|
||||||
|
l |= amt[i].iselect;
|
||||||
|
r |= amt[i].iselect >> 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,13 +627,20 @@ als_intr(void *p)
|
|||||||
struct sc_info *sc = (struct sc_info *)p;
|
struct sc_info *sc = (struct sc_info *)p;
|
||||||
u_int8_t intr, sb_status;
|
u_int8_t intr, sb_status;
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
intr = als_intr_rd(sc);
|
intr = als_intr_rd(sc);
|
||||||
|
|
||||||
if (intr & 0x80)
|
if (intr & 0x80) {
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
chn_intr(sc->pch.channel);
|
chn_intr(sc->pch.channel);
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
|
}
|
||||||
|
|
||||||
if (intr & 0x40)
|
if (intr & 0x40) {
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
chn_intr(sc->rch.channel);
|
chn_intr(sc->rch.channel);
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
|
}
|
||||||
|
|
||||||
/* ACK interrupt in PCI core */
|
/* ACK interrupt in PCI core */
|
||||||
als_intr_wr(sc, intr);
|
als_intr_wr(sc, intr);
|
||||||
@ -627,6 +656,8 @@ als_intr(void *p)
|
|||||||
als_ack_read(sc, ALS_MIDI_DATA);
|
als_ack_read(sc, ALS_MIDI_DATA);
|
||||||
if (sb_status & ALS_IRQ_CR1E)
|
if (sb_status & ALS_IRQ_CR1E)
|
||||||
als_ack_read(sc, ALS_CR1E_ACK_PORT);
|
als_ack_read(sc, ALS_CR1E_ACK_PORT);
|
||||||
|
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,6 +739,10 @@ als_resource_free(device_t dev, struct sc_info *sc)
|
|||||||
bus_dma_tag_destroy(sc->parent_dmat);
|
bus_dma_tag_destroy(sc->parent_dmat);
|
||||||
sc->parent_dmat = 0;
|
sc->parent_dmat = 0;
|
||||||
}
|
}
|
||||||
|
if (sc->lock) {
|
||||||
|
snd_mtxfree(sc->lock);
|
||||||
|
sc->lock = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -730,7 +765,7 @@ als_resource_grab(device_t dev, struct sc_info *sc)
|
|||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bus_setup_intr(dev, sc->irq, INTR_TYPE_AV, als_intr,
|
if (snd_setup_intr(dev, sc->irq, INTR_MPSAFE, als_intr,
|
||||||
sc, &sc->ih)) {
|
sc, &sc->ih)) {
|
||||||
device_printf(dev, "unable to setup interrupt\n");
|
device_printf(dev, "unable to setup interrupt\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -745,8 +780,8 @@ als_resource_grab(device_t dev, struct sc_info *sc)
|
|||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/sc->bufsz,
|
/*maxsize*/sc->bufsz,
|
||||||
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
/*flags*/0, /*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant, &sc->parent_dmat) != 0) {
|
/*lockarg*/NULL, &sc->parent_dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -768,6 +803,7 @@ als_pci_attach(device_t dev)
|
|||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
|
|
||||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||||
@ -851,9 +887,11 @@ als_pci_suspend(device_t dev)
|
|||||||
{
|
{
|
||||||
struct sc_info *sc = pcm_getdevinfo(dev);
|
struct sc_info *sc = pcm_getdevinfo(dev);
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
sc->pch.dma_was_active = als_playback_stop(&sc->pch);
|
sc->pch.dma_was_active = als_playback_stop(&sc->pch);
|
||||||
sc->rch.dma_was_active = als_capture_stop(&sc->rch);
|
sc->rch.dma_was_active = als_capture_stop(&sc->rch);
|
||||||
als_uninit(sc);
|
als_uninit(sc);
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,13 +900,17 @@ als_pci_resume(device_t dev)
|
|||||||
{
|
{
|
||||||
struct sc_info *sc = pcm_getdevinfo(dev);
|
struct sc_info *sc = pcm_getdevinfo(dev);
|
||||||
|
|
||||||
|
|
||||||
|
snd_mtxlock(sc->lock);
|
||||||
if (als_init(sc) != 0) {
|
if (als_init(sc) != 0) {
|
||||||
device_printf(dev, "unable to reinitialize the card\n");
|
device_printf(dev, "unable to reinitialize the card\n");
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mixer_reinit(dev) != 0) {
|
if (mixer_reinit(dev) != 0) {
|
||||||
device_printf(dev, "unable to reinitialize the mixer\n");
|
device_printf(dev, "unable to reinitialize the mixer\n");
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -879,6 +921,8 @@ als_pci_resume(device_t dev)
|
|||||||
if (sc->rch.dma_was_active) {
|
if (sc->rch.dma_was_active) {
|
||||||
als_capture_start(&sc->rch);
|
als_capture_start(&sc->rch);
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(sc->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,8 +876,8 @@ cmi_attach(device_t dev)
|
|||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/sc->bufsz, /*nsegments*/1,
|
/*maxsize*/sc->bufsz, /*nsegments*/1,
|
||||||
/*maxsegz*/0x3ffff, /*flags*/0,
|
/*maxsegz*/0x3ffff, /*flags*/0,
|
||||||
/*lockfunc*/busdma_lock_mutex,
|
/*lockfunc*/NULL,
|
||||||
/*lockfunc*/&Giant,
|
/*lockfunc*/NULL,
|
||||||
&sc->parent_dmat) != 0) {
|
&sc->parent_dmat) != 0) {
|
||||||
device_printf(dev, "cmi_attach: Unable to create dma tag\n");
|
device_printf(dev, "cmi_attach: Unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
|
@ -644,7 +644,7 @@ csa_initialize(sc_p scp)
|
|||||||
/*
|
/*
|
||||||
* Set the serial port FIFO pointer to the first sample in the FIFO.
|
* Set the serial port FIFO pointer to the first sample in the FIFO.
|
||||||
*/
|
*/
|
||||||
#if notdef
|
#ifdef notdef
|
||||||
csa_writeio(resp, BA0_SERBSP, 0);
|
csa_writeio(resp, BA0_SERBSP, 0);
|
||||||
#endif /* notdef */
|
#endif /* notdef */
|
||||||
|
|
||||||
@ -698,7 +698,7 @@ csa_initialize(sc_p scp)
|
|||||||
* First, lets wait a short while to let things settle out a bit,
|
* First, lets wait a short while to let things settle out a bit,
|
||||||
* and to prevent retrying the read too quickly.
|
* and to prevent retrying the read too quickly.
|
||||||
*/
|
*/
|
||||||
#if notdef
|
#ifdef notdef
|
||||||
DELAY(10000000L); /* clw */
|
DELAY(10000000L); /* clw */
|
||||||
#else
|
#else
|
||||||
DELAY(1000);
|
DELAY(1000);
|
||||||
@ -728,7 +728,7 @@ csa_initialize(sc_p scp)
|
|||||||
* Power down the DAC and ADC. We will power them up (if) when we need
|
* Power down the DAC and ADC. We will power them up (if) when we need
|
||||||
* them.
|
* them.
|
||||||
*/
|
*/
|
||||||
#if notdef
|
#ifdef notdef
|
||||||
csa_writeio(resp, BA0_AC97_POWERDOWN, 0x300);
|
csa_writeio(resp, BA0_AC97_POWERDOWN, 0x300);
|
||||||
#endif /* notdef */
|
#endif /* notdef */
|
||||||
|
|
||||||
@ -736,7 +736,7 @@ csa_initialize(sc_p scp)
|
|||||||
* Turn off the Processor by turning off the software clock enable flag in
|
* Turn off the Processor by turning off the software clock enable flag in
|
||||||
* the clock control register.
|
* the clock control register.
|
||||||
*/
|
*/
|
||||||
#if notdef
|
#ifdef notdef
|
||||||
clkcr1 = csa_readio(resp, BA0_CLKCR1) & ~CLKCR1_SWCE;
|
clkcr1 = csa_readio(resp, BA0_CLKCR1) & ~CLKCR1_SWCE;
|
||||||
csa_writeio(resp, BA0_CLKCR1, clkcr1);
|
csa_writeio(resp, BA0_CLKCR1, clkcr1);
|
||||||
#endif /* notdef */
|
#endif /* notdef */
|
||||||
|
@ -667,6 +667,14 @@ csa_init(struct csa_info *csa)
|
|||||||
/* Crank up the power on the DAC and ADC. */
|
/* Crank up the power on the DAC and ADC. */
|
||||||
csa_setplaysamplerate(resp, 8000);
|
csa_setplaysamplerate(resp, 8000);
|
||||||
csa_setcapturesamplerate(resp, 8000);
|
csa_setcapturesamplerate(resp, 8000);
|
||||||
|
/* Set defaults */
|
||||||
|
csa_writeio(resp, BA0_EGPIODR, EGPIODR_GPOE0);
|
||||||
|
csa_writeio(resp, BA0_EGPIOPTR, EGPIOPTR_GPPT0);
|
||||||
|
/* Power up amplifier */
|
||||||
|
csa_writeio(resp, BA0_EGPIODR, csa_readio(resp, BA0_EGPIODR) |
|
||||||
|
EGPIODR_GPOE2);
|
||||||
|
csa_writeio(resp, BA0_EGPIOPTR, csa_readio(resp, BA0_EGPIOPTR) |
|
||||||
|
EGPIOPTR_GPPT2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -494,12 +494,12 @@ emu_vinit(struct sc_info *sc, struct emu_voice *m, struct emu_voice *s,
|
|||||||
m->buf = tmp_addr;
|
m->buf = tmp_addr;
|
||||||
m->slave = s;
|
m->slave = s;
|
||||||
if (sc->audigy) {
|
if (sc->audigy) {
|
||||||
m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_LEFT << 8 |
|
m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_RIGHT << 8 |
|
||||||
FXBUS_PCM_RIGHT << 16 | FXBUS_MIDI_REVERB << 24;
|
FXBUS_PCM_LEFT << 16 | FXBUS_MIDI_REVERB << 24;
|
||||||
m->fxrt2 = 0x3f3f3f3f; /* No effects on second route */
|
m->fxrt2 = 0x3f3f3f3f; /* No effects on second route */
|
||||||
} else {
|
} else {
|
||||||
m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_LEFT << 4 |
|
m->fxrt1 = FXBUS_MIDI_CHORUS | FXBUS_PCM_RIGHT << 4 |
|
||||||
FXBUS_PCM_RIGHT << 8 | FXBUS_MIDI_REVERB << 12;
|
FXBUS_PCM_LEFT << 8 | FXBUS_MIDI_REVERB << 12;
|
||||||
m->fxrt2 = 0;
|
m->fxrt2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -166,6 +166,17 @@
|
|||||||
#define ES1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0) /* current value of the sample rate converter */
|
#define ES1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0) /* current value of the sample rate converter */
|
||||||
#define ES1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff) /* current value of the sample rate converter */
|
#define ES1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff) /* current value of the sample rate converter */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* S/PDIF specific
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Use ES1370_REG_CONTROL */
|
||||||
|
#define RECEN_B 0x08000000 /* Used to control mixing of analog with digital data */
|
||||||
|
#define SPDIFEN_B 0x04000000 /* Reset to switch digital output mux to "THRU" mode */
|
||||||
|
/* Use ES1370_REG_STATUS */
|
||||||
|
#define ENABLE_SPDIF 0x00040000 /* Used to enable the S/PDIF circuitry */
|
||||||
|
#define TEST_SPDIF 0x00020000 /* Used to put the S/PDIF module in "test mode" */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sample rate converter addresses
|
* Sample rate converter addresses
|
||||||
*/
|
*/
|
||||||
|
@ -41,11 +41,81 @@ SND_DECLARE_FILE("$FreeBSD$");
|
|||||||
#define ICH_DEFAULT_BUFSZ 16384
|
#define ICH_DEFAULT_BUFSZ 16384
|
||||||
#define ICH_MAX_BUFSZ 65536
|
#define ICH_MAX_BUFSZ 65536
|
||||||
|
|
||||||
#define SIS7012ID 0x70121039 /* SiS 7012 needs special handling */
|
#define INTEL_VENDORID 0x8086
|
||||||
#define ICH4ID 0x24c58086 /* ICH4 needs special handling too */
|
#define SIS_VENDORID 0x1039
|
||||||
#define ICH5ID 0x24d58086 /* ICH5 needs to be treated as ICH4 */
|
#define NVIDIA_VENDORID 0x10de
|
||||||
#define I6300ESBID 0x25a68086 /* 6300ESB needs to be treated as ICH4 */
|
#define AMD_VENDORID 0x1022
|
||||||
#define ICH6ID 0x266e8086 /* ICH6 needs to be treated as ICH4 */
|
|
||||||
|
#define INTEL_82440MX 0x7195
|
||||||
|
#define INTEL_82801AA 0x2415
|
||||||
|
#define INTEL_82801AB 0x2425
|
||||||
|
#define INTEL_82801BA 0x2445
|
||||||
|
#define INTEL_82801CA 0x2485
|
||||||
|
#define INTEL_82801DB 0x24c5 /* ICH4 needs special handling */
|
||||||
|
#define INTEL_82801EB 0x24d5 /* ICH5 needs to be treated as ICH4 */
|
||||||
|
#define INTEL_6300ESB 0x25a6 /* 6300ESB needs to be treated as ICH4 */
|
||||||
|
#define INTEL_82801FB 0x266e /* ICH6 needs to be treated as ICH4 */
|
||||||
|
#define INTEL_82801GB 0x27de /* ICH7 needs to be treated as ICH4 */
|
||||||
|
#define SIS_7012 0x7012 /* SiS 7012 needs special handling */
|
||||||
|
#define NVIDIA_NFORCE 0x01b1
|
||||||
|
#define NVIDIA_NFORCE2 0x006a
|
||||||
|
#define NVIDIA_NFORCE2_400 0x008a
|
||||||
|
#define NVIDIA_NFORCE3 0x00da
|
||||||
|
#define NVIDIA_NFORCE3_250 0x00ea
|
||||||
|
#define NVIDIA_NFORCE4 0x0059
|
||||||
|
#define AMD_768 0x7445
|
||||||
|
#define AMD_8111 0x746d
|
||||||
|
|
||||||
|
#define ICH_LOCK(sc) snd_mtxlock((sc)->ich_lock)
|
||||||
|
#define ICH_UNLOCK(sc) snd_mtxunlock((sc)->ich_lock)
|
||||||
|
#define ICH_LOCK_ASSERT(sc) snd_mtxassert((sc)->ich_lock)
|
||||||
|
|
||||||
|
static const struct ich_type {
|
||||||
|
uint16_t vendor;
|
||||||
|
uint16_t devid;
|
||||||
|
uint32_t options;
|
||||||
|
#define PROBE_LOW 0x01
|
||||||
|
char *name;
|
||||||
|
} ich_devs[] = {
|
||||||
|
{ INTEL_VENDORID, INTEL_82440MX, 0,
|
||||||
|
"Intel 440MX" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801AA, 0,
|
||||||
|
"Intel ICH (82801AA)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801AB, 0,
|
||||||
|
"Intel ICH (82801AB)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801BA, 0,
|
||||||
|
"Intel ICH2 (82801BA)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801CA, 0,
|
||||||
|
"Intel ICH3 (82801CA)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801DB, PROBE_LOW,
|
||||||
|
"Intel ICH4 (82801DB)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801EB, PROBE_LOW,
|
||||||
|
"Intel ICH5 (82801EB)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_6300ESB, PROBE_LOW,
|
||||||
|
"Intel 6300ESB" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801FB, PROBE_LOW,
|
||||||
|
"Intel ICH6 (82801FB)" },
|
||||||
|
{ INTEL_VENDORID, INTEL_82801GB, PROBE_LOW,
|
||||||
|
"Intel ICH7 (82801GB)" },
|
||||||
|
{ SIS_VENDORID, SIS_7012, 0,
|
||||||
|
"SiS 7012" },
|
||||||
|
{ NVIDIA_VENDORID, NVIDIA_NFORCE, 0,
|
||||||
|
"nVidia nForce" },
|
||||||
|
{ NVIDIA_VENDORID, NVIDIA_NFORCE2, 0,
|
||||||
|
"nVidia nForce2" },
|
||||||
|
{ NVIDIA_VENDORID, NVIDIA_NFORCE2_400, 0,
|
||||||
|
"nVidia nForce2 400" },
|
||||||
|
{ NVIDIA_VENDORID, NVIDIA_NFORCE3, 0,
|
||||||
|
"nVidia nForce3" },
|
||||||
|
{ NVIDIA_VENDORID, NVIDIA_NFORCE3_250, 0,
|
||||||
|
"nVidia nForce3 250" },
|
||||||
|
{ NVIDIA_VENDORID, NVIDIA_NFORCE4, 0,
|
||||||
|
"nVidia nForce4" },
|
||||||
|
{ AMD_VENDORID, AMD_768, 0,
|
||||||
|
"AMD-768" },
|
||||||
|
{ AMD_VENDORID, AMD_8111, 0,
|
||||||
|
"AMD-8111" }
|
||||||
|
};
|
||||||
|
|
||||||
/* buffer descriptor */
|
/* buffer descriptor */
|
||||||
struct ich_desc {
|
struct ich_desc {
|
||||||
@ -93,6 +163,11 @@ struct sc_info {
|
|||||||
bus_addr_t desc_addr;
|
bus_addr_t desc_addr;
|
||||||
struct intr_config_hook intrhook;
|
struct intr_config_hook intrhook;
|
||||||
int use_intrhook;
|
int use_intrhook;
|
||||||
|
uint16_t vendor;
|
||||||
|
uint16_t devid;
|
||||||
|
uint32_t flags;
|
||||||
|
#define IGNORE_PCR 0x01
|
||||||
|
struct mtx *ich_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@ -106,7 +181,7 @@ static struct pcmchan_caps ich_caps = {48000, 48000, ich_fmt, 0};
|
|||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* Hardware */
|
/* Hardware */
|
||||||
static u_int32_t
|
static __inline u_int32_t
|
||||||
ich_rd(struct sc_info *sc, int regno, int size)
|
ich_rd(struct sc_info *sc, int regno, int size)
|
||||||
{
|
{
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@ -121,7 +196,7 @@ ich_rd(struct sc_info *sc, int regno, int size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static __inline void
|
||||||
ich_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
|
ich_wr(struct sc_info *sc, int regno, u_int32_t data, int size)
|
||||||
{
|
{
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@ -149,7 +224,10 @@ ich_waitcd(void *devinfo)
|
|||||||
data = ich_rd(sc, ICH_REG_ACC_SEMA, 1);
|
data = ich_rd(sc, ICH_REG_ACC_SEMA, 1);
|
||||||
if ((data & 0x01) == 0)
|
if ((data & 0x01) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
DELAY(1);
|
||||||
}
|
}
|
||||||
|
if ((sc->flags & IGNORE_PCR) != 0)
|
||||||
|
return (0);
|
||||||
device_printf(sc->dev, "CODEC semaphore timeout\n");
|
device_printf(sc->dev, "CODEC semaphore timeout\n");
|
||||||
return ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
@ -190,15 +268,15 @@ AC97_DECLARE(ich_ac97);
|
|||||||
static void
|
static void
|
||||||
ich_filldtbl(struct sc_chinfo *ch)
|
ich_filldtbl(struct sc_chinfo *ch)
|
||||||
{
|
{
|
||||||
|
struct sc_info *sc = ch->parent;
|
||||||
u_int32_t base;
|
u_int32_t base;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
base = sndbuf_getbufaddr(ch->buffer);
|
base = sndbuf_getbufaddr(ch->buffer);
|
||||||
ch->blkcnt = sndbuf_getsize(ch->buffer) / ch->blksz;
|
if (ch->blksz > sc->bufsz / ch->blkcnt)
|
||||||
if (ch->blkcnt != 2 && ch->blkcnt != 4 && ch->blkcnt != 8 && ch->blkcnt != 16 && ch->blkcnt != 32) {
|
ch->blksz = sc->bufsz / ch->blkcnt;
|
||||||
ch->blkcnt = 2;
|
sndbuf_resize(ch->buffer, ch->blkcnt, ch->blksz);
|
||||||
ch->blksz = sndbuf_getsize(ch->buffer) / ch->blkcnt;
|
ch->blksz = sndbuf_getblksz(ch->buffer);
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ICH_DTBL_LENGTH; i++) {
|
for (i = 0; i < ICH_DTBL_LENGTH; i++) {
|
||||||
ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt));
|
ch->dtbl[i].buffer = base + (ch->blksz * (i % ch->blkcnt));
|
||||||
@ -222,7 +300,12 @@ ich_resetchan(struct sc_info *sc, int num)
|
|||||||
return ENXIO;
|
return ENXIO;
|
||||||
|
|
||||||
ich_wr(sc, regbase + ICH_REG_X_CR, 0, 1);
|
ich_wr(sc, regbase + ICH_REG_X_CR, 0, 1);
|
||||||
|
#if 1
|
||||||
|
/* This may result in no sound output on NForce 2 MBs, see PR 73987 */
|
||||||
DELAY(100);
|
DELAY(100);
|
||||||
|
#else
|
||||||
|
(void)ich_rd(sc, regbase + ICH_REG_X_CR, 1);
|
||||||
|
#endif
|
||||||
ich_wr(sc, regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
|
ich_wr(sc, regbase + ICH_REG_X_CR, ICH_X_CR_RR, 1);
|
||||||
for (i = 0; i < ICH_TIMEOUT; i++) {
|
for (i = 0; i < ICH_TIMEOUT; i++) {
|
||||||
cr = ich_rd(sc, regbase + ICH_REG_X_CR, 1);
|
cr = ich_rd(sc, regbase + ICH_REG_X_CR, 1);
|
||||||
@ -244,6 +327,7 @@ ichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
|
|||||||
struct sc_chinfo *ch;
|
struct sc_chinfo *ch;
|
||||||
unsigned int num;
|
unsigned int num;
|
||||||
|
|
||||||
|
ICH_LOCK(sc);
|
||||||
num = sc->chnum++;
|
num = sc->chnum++;
|
||||||
ch = &sc->ch[num];
|
ch = &sc->ch[num];
|
||||||
ch->num = num;
|
ch->num = num;
|
||||||
@ -283,10 +367,13 @@ ichchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
if (sndbuf_alloc(ch->buffer, sc->dmat, sc->bufsz) != 0)
|
if (sndbuf_alloc(ch->buffer, sc->dmat, sc->bufsz) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
ICH_LOCK(sc);
|
||||||
ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)(ch->desc_addr), 4);
|
ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)(ch->desc_addr), 4);
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
@ -304,16 +391,20 @@ ichchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
|||||||
struct sc_info *sc = ch->parent;
|
struct sc_info *sc = ch->parent;
|
||||||
|
|
||||||
if (ch->spdreg) {
|
if (ch->spdreg) {
|
||||||
int r;
|
int r, ac97rate;
|
||||||
|
|
||||||
|
ICH_LOCK(sc);
|
||||||
if (sc->ac97rate <= 32000 || sc->ac97rate >= 64000)
|
if (sc->ac97rate <= 32000 || sc->ac97rate >= 64000)
|
||||||
sc->ac97rate = 48000;
|
sc->ac97rate = 48000;
|
||||||
r = (speed * 48000) / sc->ac97rate;
|
ac97rate = sc->ac97rate;
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
|
r = (speed * 48000) / ac97rate;
|
||||||
/*
|
/*
|
||||||
* Cast the return value of ac97_setrate() to u_int so that
|
* Cast the return value of ac97_setrate() to u_int so that
|
||||||
* the math don't overflow into the negative range.
|
* the math don't overflow into the negative range.
|
||||||
*/
|
*/
|
||||||
ch->spd = ((u_int)ac97_setrate(sc->codec, ch->spdreg, r) *
|
ch->spd = ((u_int)ac97_setrate(sc->codec, ch->spdreg, r) *
|
||||||
sc->ac97rate) / 48000;
|
ac97rate) / 48000;
|
||||||
} else {
|
} else {
|
||||||
ch->spd = 48000;
|
ch->spd = 48000;
|
||||||
}
|
}
|
||||||
@ -328,7 +419,9 @@ ichchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
|
|||||||
|
|
||||||
ch->blksz = blocksize;
|
ch->blksz = blocksize;
|
||||||
ich_filldtbl(ch);
|
ich_filldtbl(ch);
|
||||||
|
ICH_LOCK(sc);
|
||||||
ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ch->blkcnt - 1, 1);
|
ich_wr(sc, ch->regbase + ICH_REG_X_LVI, ch->blkcnt - 1, 1);
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
|
|
||||||
return ch->blksz;
|
return ch->blksz;
|
||||||
}
|
}
|
||||||
@ -342,12 +435,16 @@ ichchan_trigger(kobj_t obj, void *data, int go)
|
|||||||
switch (go) {
|
switch (go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
ch->run = 1;
|
ch->run = 1;
|
||||||
|
ICH_LOCK(sc);
|
||||||
ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)(ch->desc_addr), 4);
|
ich_wr(sc, ch->regbase + ICH_REG_X_BDBAR, (u_int32_t)(ch->desc_addr), 4);
|
||||||
ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE, 1);
|
ich_wr(sc, ch->regbase + ICH_REG_X_CR, ICH_X_CR_RPBM | ICH_X_CR_LVBIE | ICH_X_CR_IOCE, 1);
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCMTRIG_ABORT:
|
case PCMTRIG_ABORT:
|
||||||
|
ICH_LOCK(sc);
|
||||||
ich_resetchan(sc, ch->num);
|
ich_resetchan(sc, ch->num);
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
ch->run = 0;
|
ch->run = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -361,7 +458,9 @@ ichchan_getptr(kobj_t obj, void *data)
|
|||||||
struct sc_info *sc = ch->parent;
|
struct sc_info *sc = ch->parent;
|
||||||
u_int32_t pos;
|
u_int32_t pos;
|
||||||
|
|
||||||
|
ICH_LOCK(sc);
|
||||||
ch->civ = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1) % ch->blkcnt;
|
ch->civ = ich_rd(sc, ch->regbase + ICH_REG_X_CIV, 1) % ch->blkcnt;
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
|
|
||||||
pos = ch->civ * ch->blksz;
|
pos = ch->civ * ch->blksz;
|
||||||
|
|
||||||
@ -399,6 +498,7 @@ ich_intr(void *p)
|
|||||||
u_int32_t cbi, lbi, lvi, st, gs;
|
u_int32_t cbi, lbi, lvi, st, gs;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
ICH_LOCK(sc);
|
||||||
gs = ich_rd(sc, ICH_REG_GLOB_STA, 4) & ICH_GLOB_STA_IMASK;
|
gs = ich_rd(sc, ICH_REG_GLOB_STA, 4) & ICH_GLOB_STA_IMASK;
|
||||||
if (gs & (ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES)) {
|
if (gs & (ICH_GLOB_STA_PRES | ICH_GLOB_STA_SRES)) {
|
||||||
/* Clear resume interrupt(s) - nothing doing with them */
|
/* Clear resume interrupt(s) - nothing doing with them */
|
||||||
@ -417,8 +517,11 @@ ich_intr(void *p)
|
|||||||
st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI;
|
st &= ICH_X_SR_FIFOE | ICH_X_SR_BCIS | ICH_X_SR_LVBCI;
|
||||||
if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
|
if (st & (ICH_X_SR_BCIS | ICH_X_SR_LVBCI)) {
|
||||||
/* block complete - update buffer */
|
/* block complete - update buffer */
|
||||||
if (ch->run)
|
if (ch->run) {
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
chn_intr(ch->channel);
|
chn_intr(ch->channel);
|
||||||
|
ICH_LOCK(sc);
|
||||||
|
}
|
||||||
lvi = ich_rd(sc, ch->regbase + ICH_REG_X_LVI, 1);
|
lvi = ich_rd(sc, ch->regbase + ICH_REG_X_LVI, 1);
|
||||||
cbi = ch->civ % ch->blkcnt;
|
cbi = ch->civ % ch->blkcnt;
|
||||||
if (cbi == 0)
|
if (cbi == 0)
|
||||||
@ -439,6 +542,7 @@ ich_intr(void *p)
|
|||||||
(sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),
|
(sc->swap_reg ? ICH_REG_X_PICB : ICH_REG_X_SR),
|
||||||
st, 2);
|
st, 2);
|
||||||
}
|
}
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
if (gs != 0) {
|
if (gs != 0) {
|
||||||
device_printf(sc->dev,
|
device_printf(sc->dev,
|
||||||
"Unhandled interrupt, gs_intr = %x\n", gs);
|
"Unhandled interrupt, gs_intr = %x\n", gs);
|
||||||
@ -581,11 +685,12 @@ ich_init(struct sc_info *sc)
|
|||||||
|
|
||||||
if ((stat & ICH_GLOB_STA_PCR) == 0) {
|
if ((stat & ICH_GLOB_STA_PCR) == 0) {
|
||||||
/* ICH4/ICH5 may fail when busmastering is enabled. Continue */
|
/* ICH4/ICH5 may fail when busmastering is enabled. Continue */
|
||||||
if ((pci_get_devid(sc->dev) != ICH4ID) &&
|
if (sc->vendor == INTEL_VENDORID && (
|
||||||
(pci_get_devid(sc->dev) != ICH5ID) &&
|
sc->devid == INTEL_82801DB || sc->devid == INTEL_82801EB ||
|
||||||
(pci_get_devid(sc->dev) != I6300ESBID) &&
|
sc->devid == INTEL_6300ESB || sc->devid == INTEL_82801FB ||
|
||||||
(pci_get_devid(sc->dev) != ICH6ID)) {
|
sc->devid == INTEL_82801GB)) {
|
||||||
return ENXIO;
|
sc->flags |= IGNORE_PCR;
|
||||||
|
device_printf(sc->dev, "primary codec not ready!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,104 +716,47 @@ ich_init(struct sc_info *sc)
|
|||||||
static int
|
static int
|
||||||
ich_pci_probe(device_t dev)
|
ich_pci_probe(device_t dev)
|
||||||
{
|
{
|
||||||
switch(pci_get_devid(dev)) {
|
int i;
|
||||||
case 0x71958086:
|
uint16_t devid, vendor;
|
||||||
device_set_desc(dev, "Intel 443MX");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x24158086:
|
vendor = pci_get_vendor(dev);
|
||||||
device_set_desc(dev, "Intel ICH (82801AA)");
|
devid = pci_get_device(dev);
|
||||||
return BUS_PROBE_DEFAULT;
|
for (i = 0; i < sizeof(ich_devs)/sizeof(ich_devs[0]); i++) {
|
||||||
|
if (vendor == ich_devs[i].vendor &&
|
||||||
case 0x24258086:
|
devid == ich_devs[i].devid) {
|
||||||
device_set_desc(dev, "Intel ICH (82801AB)");
|
device_set_desc(dev, ich_devs[i].name);
|
||||||
return BUS_PROBE_DEFAULT;
|
/* allow a better driver to override us */
|
||||||
|
if ((ich_devs[i].options & PROBE_LOW) != 0)
|
||||||
case 0x24458086:
|
return (BUS_PROBE_LOW_PRIORITY);
|
||||||
device_set_desc(dev, "Intel ICH2 (82801BA)");
|
return (BUS_PROBE_DEFAULT);
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x24858086:
|
|
||||||
device_set_desc(dev, "Intel ICH3 (82801CA)");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case ICH4ID:
|
|
||||||
device_set_desc(dev, "Intel ICH4 (82801DB)");
|
|
||||||
return BUS_PROBE_LOW_PRIORITY;
|
|
||||||
|
|
||||||
case ICH5ID:
|
|
||||||
device_set_desc(dev, "Intel ICH5 (82801EB)");
|
|
||||||
return BUS_PROBE_LOW_PRIORITY;
|
|
||||||
|
|
||||||
case I6300ESBID:
|
|
||||||
device_set_desc(dev, "Intel 6300ESB");
|
|
||||||
return BUS_PROBE_LOW_PRIORITY;
|
|
||||||
|
|
||||||
case ICH6ID:
|
|
||||||
device_set_desc(dev, "Intel ICH6 (82801FB)");
|
|
||||||
return BUS_PROBE_LOW_PRIORITY;
|
|
||||||
|
|
||||||
case SIS7012ID:
|
|
||||||
device_set_desc(dev, "SiS 7012");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x01b110de:
|
|
||||||
device_set_desc(dev, "nVidia nForce");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x006a10de:
|
|
||||||
device_set_desc(dev, "nVidia nForce2");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x008a10de:
|
|
||||||
device_set_desc(dev, "nVidia nForce2 400");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x00da10de:
|
|
||||||
device_set_desc(dev, "nVidia nForce3");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x00ea10de:
|
|
||||||
device_set_desc(dev, "nVidia nForce3 250");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x005910de:
|
|
||||||
device_set_desc(dev, "nVidia nForce4");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x74451022:
|
|
||||||
device_set_desc(dev, "AMD-768");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
case 0x746d1022:
|
|
||||||
device_set_desc(dev, "AMD-8111");
|
|
||||||
return BUS_PROBE_DEFAULT;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return ENXIO;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return (ENXIO);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ich_pci_attach(device_t dev)
|
ich_pci_attach(device_t dev)
|
||||||
{
|
{
|
||||||
u_int16_t extcaps;
|
u_int16_t extcaps;
|
||||||
|
uint16_t devid, vendor;
|
||||||
struct sc_info *sc;
|
struct sc_info *sc;
|
||||||
char status[SND_STATUSLEN];
|
char status[SND_STATUSLEN];
|
||||||
|
|
||||||
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT)) == NULL) {
|
if ((sc = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
|
||||||
device_printf(dev, "cannot allocate softc\n");
|
device_printf(dev, "cannot allocate softc\n");
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
bzero(sc, sizeof(*sc));
|
sc->ich_lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
|
||||||
sc->dev = dev;
|
sc->dev = dev;
|
||||||
|
|
||||||
|
vendor = sc->vendor = pci_get_vendor(dev);
|
||||||
|
devid = sc->devid = pci_get_device(dev);
|
||||||
/*
|
/*
|
||||||
* The SiS 7012 register set isn't quite like the standard ich.
|
* The SiS 7012 register set isn't quite like the standard ich.
|
||||||
* There really should be a general "quirks" mechanism.
|
* There really should be a general "quirks" mechanism.
|
||||||
*/
|
*/
|
||||||
if (pci_get_devid(dev) == SIS7012ID) {
|
if (vendor == SIS_VENDORID && devid == SIS_7012) {
|
||||||
sc->swap_reg = 1;
|
sc->swap_reg = 1;
|
||||||
sc->sample_size = 1;
|
sc->sample_size = 1;
|
||||||
} else {
|
} else {
|
||||||
@ -716,6 +764,12 @@ ich_pci_attach(device_t dev)
|
|||||||
sc->sample_size = 2;
|
sc->sample_size = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable bus master. On ich4/5 this may prevent the detection of
|
||||||
|
* the primary codec becoming ready in ich_init().
|
||||||
|
*/
|
||||||
|
pci_enable_busmaster(dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By default, ich4 has NAMBAR and NABMBAR i/o spaces as
|
* By default, ich4 has NAMBAR and NABMBAR i/o spaces as
|
||||||
* read-only. Need to enable "legacy support", by poking into
|
* read-only. Need to enable "legacy support", by poking into
|
||||||
@ -723,22 +777,13 @@ ich_pci_attach(device_t dev)
|
|||||||
* but doing so will mess things up here. ich4 has enough new
|
* but doing so will mess things up here. ich4 has enough new
|
||||||
* features it warrants it's own driver.
|
* features it warrants it's own driver.
|
||||||
*/
|
*/
|
||||||
if (pci_get_devid(dev) == ICH4ID) {
|
if (vendor == INTEL_VENDORID && (devid == INTEL_82801DB ||
|
||||||
pci_write_config(dev, PCIR_ICH_LEGACY, ICH_LEGACY_ENABLE, 1);
|
devid == INTEL_82801EB || devid == INTEL_6300ESB ||
|
||||||
}
|
devid == INTEL_82801FB || devid == INTEL_82801GB)) {
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable bus master. On ich4/5 this may prevent the detection of
|
|
||||||
* the primary codec becoming ready in ich_init().
|
|
||||||
*/
|
|
||||||
pci_enable_busmaster(dev);
|
|
||||||
|
|
||||||
if (pci_get_devid(dev) == ICH5ID ||
|
|
||||||
pci_get_devid(dev) == I6300ESBID ||
|
|
||||||
pci_get_devid(dev) == ICH6ID) {
|
|
||||||
sc->nambarid = PCIR_MMBAR;
|
sc->nambarid = PCIR_MMBAR;
|
||||||
sc->nabmbarid = PCIR_MBBAR;
|
sc->nabmbarid = PCIR_MBBAR;
|
||||||
sc->regtype = SYS_RES_MEMORY;
|
sc->regtype = SYS_RES_MEMORY;
|
||||||
|
pci_write_config(dev, PCIR_ICH_LEGACY, ICH_LEGACY_ENABLE, 1);
|
||||||
} else {
|
} else {
|
||||||
sc->nambarid = PCIR_NAMBAR;
|
sc->nambarid = PCIR_NAMBAR;
|
||||||
sc->nabmbarid = PCIR_NABMBAR;
|
sc->nabmbarid = PCIR_NABMBAR;
|
||||||
@ -763,7 +808,7 @@ ich_pci_attach(device_t dev)
|
|||||||
sc->bufsz = pcm_getbuffersize(dev, 4096, ICH_DEFAULT_BUFSZ, ICH_MAX_BUFSZ);
|
sc->bufsz = pcm_getbuffersize(dev, 4096, ICH_DEFAULT_BUFSZ, ICH_MAX_BUFSZ);
|
||||||
if (bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
|
if (bus_dma_tag_create(NULL, 8, 0, BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
|
||||||
NULL, NULL, sc->bufsz, 1, 0x3ffff, 0,
|
NULL, NULL, sc->bufsz, 1, 0x3ffff, 0,
|
||||||
busdma_lock_mutex, &Giant, &sc->dmat) != 0) {
|
NULL, NULL, &sc->dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -771,7 +816,7 @@ ich_pci_attach(device_t dev)
|
|||||||
sc->irqid = 0;
|
sc->irqid = 0;
|
||||||
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
|
sc->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
|
||||||
RF_ACTIVE | RF_SHAREABLE);
|
RF_ACTIVE | RF_SHAREABLE);
|
||||||
if (!sc->irq || snd_setup_intr(dev, sc->irq, 0, ich_intr, sc, &sc->ih)) {
|
if (!sc->irq || snd_setup_intr(dev, sc->irq, INTR_MPSAFE, ich_intr, sc, &sc->ih)) {
|
||||||
device_printf(dev, "unable to map interrupt\n");
|
device_printf(dev, "unable to map interrupt\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -832,6 +877,8 @@ ich_pci_attach(device_t dev)
|
|||||||
if (sc->nabmbar)
|
if (sc->nabmbar)
|
||||||
bus_release_resource(dev, sc->regtype,
|
bus_release_resource(dev, sc->regtype,
|
||||||
sc->nabmbarid, sc->nabmbar);
|
sc->nabmbarid, sc->nabmbar);
|
||||||
|
if (sc->ich_lock)
|
||||||
|
snd_mtxfree(sc->ich_lock);
|
||||||
free(sc, M_DEVBUF);
|
free(sc, M_DEVBUF);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -852,6 +899,7 @@ ich_pci_detach(device_t dev)
|
|||||||
bus_release_resource(dev, sc->regtype, sc->nambarid, sc->nambar);
|
bus_release_resource(dev, sc->regtype, sc->nambarid, sc->nambar);
|
||||||
bus_release_resource(dev, sc->regtype, sc->nabmbarid, sc->nabmbar);
|
bus_release_resource(dev, sc->regtype, sc->nabmbarid, sc->nabmbar);
|
||||||
bus_dma_tag_destroy(sc->dmat);
|
bus_dma_tag_destroy(sc->dmat);
|
||||||
|
snd_mtxfree(sc->ich_lock);
|
||||||
free(sc, M_DEVBUF);
|
free(sc, M_DEVBUF);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -885,12 +933,16 @@ ich_pci_suspend(device_t dev)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
sc = pcm_getdevinfo(dev);
|
sc = pcm_getdevinfo(dev);
|
||||||
|
ICH_LOCK(sc);
|
||||||
for (i = 0 ; i < 3; i++) {
|
for (i = 0 ; i < 3; i++) {
|
||||||
sc->ch[i].run_save = sc->ch[i].run;
|
sc->ch[i].run_save = sc->ch[i].run;
|
||||||
if (sc->ch[i].run) {
|
if (sc->ch[i].run) {
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
ichchan_trigger(0, &sc->ch[i], PCMTRIG_ABORT);
|
ichchan_trigger(0, &sc->ch[i], PCMTRIG_ABORT);
|
||||||
|
ICH_LOCK(sc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -908,9 +960,11 @@ ich_pci_resume(device_t dev)
|
|||||||
pci_enable_io(dev, SYS_RES_MEMORY);
|
pci_enable_io(dev, SYS_RES_MEMORY);
|
||||||
pci_enable_busmaster(dev);
|
pci_enable_busmaster(dev);
|
||||||
|
|
||||||
|
ICH_LOCK(sc);
|
||||||
/* Reinit audio device */
|
/* Reinit audio device */
|
||||||
if (ich_init(sc) == -1) {
|
if (ich_init(sc) == -1) {
|
||||||
device_printf(dev, "unable to reinitialize the card\n");
|
device_printf(dev, "unable to reinitialize the card\n");
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
/* Reinit mixer */
|
/* Reinit mixer */
|
||||||
@ -918,17 +972,21 @@ ich_pci_resume(device_t dev)
|
|||||||
ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm);
|
ac97_setextmode(sc->codec, sc->hasvra | sc->hasvrm);
|
||||||
if (mixer_reinit(dev) == -1) {
|
if (mixer_reinit(dev) == -1) {
|
||||||
device_printf(dev, "unable to reinitialize the mixer\n");
|
device_printf(dev, "unable to reinitialize the mixer\n");
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
/* Re-start DMA engines */
|
/* Re-start DMA engines */
|
||||||
for (i = 0 ; i < 3; i++) {
|
for (i = 0 ; i < 3; i++) {
|
||||||
struct sc_chinfo *ch = &sc->ch[i];
|
struct sc_chinfo *ch = &sc->ch[i];
|
||||||
if (sc->ch[i].run_save) {
|
if (sc->ch[i].run_save) {
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
ichchan_setblocksize(0, ch, ch->blksz);
|
ichchan_setblocksize(0, ch, ch->blksz);
|
||||||
ichchan_setspeed(0, ch, ch->spd);
|
ichchan_setspeed(0, ch, ch->spd);
|
||||||
ichchan_trigger(0, ch, PCMTRIG_START);
|
ichchan_trigger(0, ch, PCMTRIG_START);
|
||||||
|
ICH_LOCK(sc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ICH_UNLOCK(sc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +223,16 @@ nm_initcd(kobj_t obj, void *devinfo)
|
|||||||
struct sc_info *sc = (struct sc_info *)devinfo;
|
struct sc_info *sc = (struct sc_info *)devinfo;
|
||||||
|
|
||||||
nm_wr(sc, 0x6c0, 0x01, 1);
|
nm_wr(sc, 0x6c0, 0x01, 1);
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* The following code-line may cause a hang for some chipsets, see
|
||||||
|
* PR 56617.
|
||||||
|
* In case of a bugreport without this line have a look at the PR and
|
||||||
|
* conditionize the code-line based upon the specific version of
|
||||||
|
* the chip.
|
||||||
|
*/
|
||||||
nm_wr(sc, 0x6cc, 0x87, 1);
|
nm_wr(sc, 0x6cc, 0x87, 1);
|
||||||
|
#endif
|
||||||
nm_wr(sc, 0x6cc, 0x80, 1);
|
nm_wr(sc, 0x6cc, 0x80, 1);
|
||||||
nm_wr(sc, 0x6cc, 0x00, 1);
|
nm_wr(sc, 0x6cc, 0x00, 1);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -100,12 +100,14 @@ struct via_info {
|
|||||||
struct ac97_info *codec;
|
struct ac97_info *codec;
|
||||||
|
|
||||||
unsigned int bufsz;
|
unsigned int bufsz;
|
||||||
|
int dxs_src;
|
||||||
|
|
||||||
struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
|
struct via_chinfo pch[NDXSCHANS + NMSGDCHANS];
|
||||||
struct via_chinfo rch[NWRCHANS];
|
struct via_chinfo rch[NWRCHANS];
|
||||||
struct via_dma_op *sgd_table;
|
struct via_dma_op *sgd_table;
|
||||||
u_int16_t codec_caps;
|
u_int16_t codec_caps;
|
||||||
u_int16_t n_dxs_registered;
|
u_int16_t n_dxs_registered;
|
||||||
|
struct mtx *lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u_int32_t via_fmt[] = {
|
static u_int32_t via_fmt[] = {
|
||||||
@ -119,7 +121,90 @@ static u_int32_t via_fmt[] = {
|
|||||||
static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
|
static struct pcmchan_caps via_vracaps = { 4000, 48000, via_fmt, 0 };
|
||||||
static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
|
static struct pcmchan_caps via_caps = { 48000, 48000, via_fmt, 0 };
|
||||||
|
|
||||||
static u_int32_t
|
#ifdef SND_DYNSYSCTL
|
||||||
|
static int
|
||||||
|
sysctl_via8233_spdif_enable(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct via_info *via;
|
||||||
|
device_t dev;
|
||||||
|
uint32_t r;
|
||||||
|
int err, new_en;
|
||||||
|
|
||||||
|
dev = oidp->oid_arg1;
|
||||||
|
via = pcm_getdevinfo(dev);
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
|
r = pci_read_config(dev, VIA_PCI_SPDIF, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
new_en = (r & VIA_SPDIF_EN) ? 1 : 0;
|
||||||
|
err = sysctl_handle_int(oidp, &new_en, sizeof(new_en), req);
|
||||||
|
|
||||||
|
if (err || req->newptr == NULL)
|
||||||
|
return err;
|
||||||
|
if (new_en < 0 || new_en > 1)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (new_en)
|
||||||
|
r |= VIA_SPDIF_EN;
|
||||||
|
else
|
||||||
|
r &= ~VIA_SPDIF_EN;
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
|
pci_write_config(dev, VIA_PCI_SPDIF, r, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int
|
||||||
|
sysctl_via8233_dxs_src(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct via_info *via;
|
||||||
|
device_t dev;
|
||||||
|
int err, val;
|
||||||
|
|
||||||
|
dev = oidp->oid_arg1;
|
||||||
|
via = pcm_getdevinfo(dev);
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
|
val = via->dxs_src;
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
err = sysctl_handle_int(oidp, &val, sizeof(val), req);
|
||||||
|
|
||||||
|
if (err || req->newptr == NULL)
|
||||||
|
return err;
|
||||||
|
if (val < 0 || val > 1)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
|
via->dxs_src = val;
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* SND_DYNSYSCTL */
|
||||||
|
|
||||||
|
static void
|
||||||
|
via_init_sysctls(device_t dev)
|
||||||
|
{
|
||||||
|
#ifdef SND_DYNSYSCTL
|
||||||
|
SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
|
||||||
|
SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
||||||
|
OID_AUTO, "spdif_enabled",
|
||||||
|
CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
|
||||||
|
sysctl_via8233_spdif_enable, "I",
|
||||||
|
"Enable S/PDIF output on primary playback channel");
|
||||||
|
#if 0
|
||||||
|
SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
|
||||||
|
SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
||||||
|
OID_AUTO, "via_dxs_src",
|
||||||
|
CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
|
||||||
|
sysctl_via8233_dxs_src, "I",
|
||||||
|
"Enable VIA DXS Sample Rate Converter");
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static __inline u_int32_t
|
||||||
via_rd(struct via_info *via, int regno, int size)
|
via_rd(struct via_info *via, int regno, int size)
|
||||||
{
|
{
|
||||||
switch (size) {
|
switch (size) {
|
||||||
@ -134,7 +219,7 @@ via_rd(struct via_info *via, int regno, int size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static __inline void
|
||||||
via_wr(struct via_info *via, int regno, u_int32_t data, int size)
|
via_wr(struct via_info *via, int regno, u_int32_t data, int size)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -260,7 +345,9 @@ via8233wr_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
f |= WR_FORMAT_STEREO;
|
f |= WR_FORMAT_STEREO;
|
||||||
if (format & AFMT_S16_LE)
|
if (format & AFMT_S16_LE)
|
||||||
f |= WR_FORMAT_16BIT;
|
f |= WR_FORMAT_16BIT;
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
via_wr(via, VIA_WR0_FORMAT, f, 4);
|
via_wr(via, VIA_WR0_FORMAT, f, 4);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -270,9 +357,11 @@ via8233dxs_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
{
|
{
|
||||||
struct via_chinfo *ch = data;
|
struct via_chinfo *ch = data;
|
||||||
struct via_info *via = ch->parent;
|
struct via_info *via = ch->parent;
|
||||||
|
u_int32_t r, v;
|
||||||
|
|
||||||
u_int32_t r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
|
r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
|
||||||
u_int32_t v = via_rd(via, r, 4);
|
snd_mtxlock(via->lock);
|
||||||
|
v = via_rd(via, r, 4);
|
||||||
|
|
||||||
v &= ~(VIA8233_DXS_RATEFMT_STEREO | VIA8233_DXS_RATEFMT_16BIT);
|
v &= ~(VIA8233_DXS_RATEFMT_STEREO | VIA8233_DXS_RATEFMT_16BIT);
|
||||||
if (format & AFMT_STEREO)
|
if (format & AFMT_STEREO)
|
||||||
@ -280,6 +369,7 @@ via8233dxs_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
if (format & AFMT_16BIT)
|
if (format & AFMT_16BIT)
|
||||||
v |= VIA8233_DXS_RATEFMT_16BIT;
|
v |= VIA8233_DXS_RATEFMT_16BIT;
|
||||||
via_wr(via, r, v, 4);
|
via_wr(via, r, v, 4);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -301,8 +391,10 @@ via8233msgd_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
s |= SLOT3(1) | SLOT4(1);
|
s |= SLOT3(1) | SLOT4(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
|
via_wr(via, VIA_MC_SLOT_SELECT, s, 4);
|
||||||
via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
|
via_wr(via, VIA_MC_SGD_FORMAT, v, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -316,11 +408,10 @@ via8233wr_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
|||||||
struct via_chinfo *ch = data;
|
struct via_chinfo *ch = data;
|
||||||
struct via_info *via = ch->parent;
|
struct via_info *via = ch->parent;
|
||||||
|
|
||||||
u_int32_t spd = 48000;
|
if (via->codec_caps & AC97_EXTCAP_VRA)
|
||||||
if (via->codec_caps & AC97_EXTCAP_VRA) {
|
return ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed);
|
||||||
spd = ac97_setrate(via->codec, AC97_REGEXT_LADCRATE, speed);
|
|
||||||
}
|
return 48000;
|
||||||
return spd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -328,14 +419,17 @@ via8233dxs_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
|||||||
{
|
{
|
||||||
struct via_chinfo *ch = data;
|
struct via_chinfo *ch = data;
|
||||||
struct via_info *via = ch->parent;
|
struct via_info *via = ch->parent;
|
||||||
|
u_int32_t r, v;
|
||||||
|
|
||||||
u_int32_t r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
|
r = ch->rbase + VIA8233_RP_DXS_RATEFMT;
|
||||||
u_int32_t v = via_rd(via, r, 4) & ~VIA8233_DXS_RATEFMT_48K;
|
snd_mtxlock(via->lock);
|
||||||
|
v = via_rd(via, r, 4) & ~VIA8233_DXS_RATEFMT_48K;
|
||||||
|
|
||||||
/* Careful to avoid overflow (divide by 48 per vt8233c docs) */
|
/* Careful to avoid overflow (divide by 48 per vt8233c docs) */
|
||||||
|
|
||||||
v |= VIA8233_DXS_RATEFMT_48K * (speed / 48) / (48000 / 48);
|
v |= VIA8233_DXS_RATEFMT_48K * (speed / 48) / (48000 / 48);
|
||||||
via_wr(via, r, v, 4);
|
via_wr(via, r, v, 4);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
@ -370,7 +464,17 @@ via8233wr_getcaps(kobj_t obj, void *data)
|
|||||||
static struct pcmchan_caps *
|
static struct pcmchan_caps *
|
||||||
via8233dxs_getcaps(kobj_t obj, void *data)
|
via8233dxs_getcaps(kobj_t obj, void *data)
|
||||||
{
|
{
|
||||||
/* Controlled by onboard registers */
|
struct via_chinfo *ch = data;
|
||||||
|
struct via_info *via = ch->parent;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Controlled by onboard registers
|
||||||
|
*
|
||||||
|
* Apparently, few boards can do DXS sample rate
|
||||||
|
* conversion.
|
||||||
|
*/
|
||||||
|
if (via->dxs_src)
|
||||||
|
return &via_vracaps;
|
||||||
return &via_caps;
|
return &via_caps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,6 +497,7 @@ static int
|
|||||||
via8233chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
|
via8233chan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
|
||||||
{
|
{
|
||||||
struct via_chinfo *ch = data;
|
struct via_chinfo *ch = data;
|
||||||
|
|
||||||
sndbuf_resize(ch->buffer, SEGS_PER_CHAN, blocksize);
|
sndbuf_resize(ch->buffer, SEGS_PER_CHAN, blocksize);
|
||||||
ch->blksz = sndbuf_getblksz(ch->buffer);
|
ch->blksz = sndbuf_getblksz(ch->buffer);
|
||||||
return ch->blksz;
|
return ch->blksz;
|
||||||
@ -403,11 +508,15 @@ via8233chan_getptr(kobj_t obj, void *data)
|
|||||||
{
|
{
|
||||||
struct via_chinfo *ch = data;
|
struct via_chinfo *ch = data;
|
||||||
struct via_info *via = ch->parent;
|
struct via_info *via = ch->parent;
|
||||||
|
u_int32_t v, index, count;
|
||||||
|
int ptr;
|
||||||
|
|
||||||
u_int32_t v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
|
snd_mtxlock(via->lock);
|
||||||
u_int32_t index = v >> 24; /* Last completed buffer */
|
v = via_rd(via, ch->rbase + VIA_RP_CURRENT_COUNT, 4);
|
||||||
u_int32_t count = v & 0x00ffffff; /* Bytes remaining */
|
snd_mtxunlock(via->lock);
|
||||||
int ptr = (index + 1) * ch->blksz - count;
|
index = v >> 24; /* Last completed buffer */
|
||||||
|
count = v & 0x00ffffff; /* Bytes remaining */
|
||||||
|
ptr = (index + 1) * ch->blksz - count;
|
||||||
ptr %= SEGS_PER_CHAN * ch->blksz; /* Wrap to available space */
|
ptr %= SEGS_PER_CHAN * ch->blksz; /* Wrap to available space */
|
||||||
|
|
||||||
return ptr;
|
return ptr;
|
||||||
@ -445,12 +554,17 @@ via8233wr_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
|
|||||||
ch->dir = dir;
|
ch->dir = dir;
|
||||||
|
|
||||||
ch->rbase = VIA_WR_BASE(c->num);
|
ch->rbase = VIA_WR_BASE(c->num);
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
via_wr(via, ch->rbase + VIA_WR_RP_SGD_FORMAT, WR_FIFO_ENABLE, 1);
|
via_wr(via, ch->rbase + VIA_WR_RP_SGD_FORMAT, WR_FIFO_ENABLE, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
via8233chan_sgdinit(via, ch, c->num);
|
via8233chan_sgdinit(via, ch, c->num);
|
||||||
via8233chan_reset(via, ch);
|
via8233chan_reset(via, ch);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
@ -472,13 +586,18 @@ via8233dxs_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
|
|||||||
* channels. We therefore want to align first DXS channel to
|
* channels. We therefore want to align first DXS channel to
|
||||||
* DXS3.
|
* DXS3.
|
||||||
*/
|
*/
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
ch->rbase = VIA_DXS_BASE(NDXSCHANS - 1 - via->n_dxs_registered);
|
ch->rbase = VIA_DXS_BASE(NDXSCHANS - 1 - via->n_dxs_registered);
|
||||||
via->n_dxs_registered++;
|
via->n_dxs_registered++;
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
|
via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
|
||||||
via8233chan_reset(via, ch);
|
via8233chan_reset(via, ch);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
@ -498,8 +617,11 @@ via8233msgd_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
|
|||||||
|
|
||||||
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
|
via8233chan_sgdinit(via, ch, NWRCHANS + c->num);
|
||||||
via8233chan_reset(via, ch);
|
via8233chan_reset(via, ch);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
@ -526,6 +648,7 @@ via8233chan_trigger(kobj_t obj, void* data, int go)
|
|||||||
struct via_chinfo *ch = data;
|
struct via_chinfo *ch = data;
|
||||||
struct via_info *via = ch->parent;
|
struct via_info *via = ch->parent;
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
switch(go) {
|
switch(go) {
|
||||||
case PCMTRIG_START:
|
case PCMTRIG_START:
|
||||||
via_buildsgdt(ch);
|
via_buildsgdt(ch);
|
||||||
@ -542,6 +665,7 @@ via8233chan_trigger(kobj_t obj, void* data, int go)
|
|||||||
via8233chan_reset(via, ch);
|
via8233chan_reset(via, ch);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,26 +714,32 @@ via_intr(void *p)
|
|||||||
int i, stat;
|
int i, stat;
|
||||||
|
|
||||||
/* Poll playback channels */
|
/* Poll playback channels */
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
|
for (i = 0; i < NDXSCHANS + NMSGDCHANS; i++) {
|
||||||
if (via->pch[i].rbase == 0)
|
if (via->pch[i].channel == NULL)
|
||||||
continue;
|
continue;
|
||||||
stat = via->pch[i].rbase + VIA_RP_STATUS;
|
stat = via->pch[i].rbase + VIA_RP_STATUS;
|
||||||
if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
|
if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
|
||||||
via_wr(via, stat, SGD_STATUS_INTR, 1);
|
via_wr(via, stat, SGD_STATUS_INTR, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
chn_intr(via->pch[i].channel);
|
chn_intr(via->pch[i].channel);
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Poll record channels */
|
/* Poll record channels */
|
||||||
for (i = 0; i < NWRCHANS; i++) {
|
for (i = 0; i < NWRCHANS; i++) {
|
||||||
if (via->rch[i].rbase == 0)
|
if (via->rch[i].channel == NULL)
|
||||||
continue;
|
continue;
|
||||||
stat = via->rch[i].rbase + VIA_RP_STATUS;
|
stat = via->rch[i].rbase + VIA_RP_STATUS;
|
||||||
if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
|
if (via_rd(via, stat, 1) & SGD_STATUS_INTR) {
|
||||||
via_wr(via, stat, SGD_STATUS_INTR, 1);
|
via_wr(via, stat, SGD_STATUS_INTR, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
chn_intr(via->rch[i].channel);
|
chn_intr(via->rch[i].channel);
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -710,61 +840,18 @@ via_chip_init(device_t dev)
|
|||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SND_DYNSYSCTL
|
|
||||||
static int via8233_spdif_en;
|
|
||||||
|
|
||||||
static int
|
|
||||||
sysctl_via8233_spdif_enable(SYSCTL_HANDLER_ARGS)
|
|
||||||
{
|
|
||||||
device_t dev;
|
|
||||||
int err, new_en, r;
|
|
||||||
|
|
||||||
new_en = via8233_spdif_en;
|
|
||||||
err = sysctl_handle_int(oidp, &new_en, sizeof(new_en), req);
|
|
||||||
if (err || req->newptr == NULL)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (new_en < 0 || new_en > 1)
|
|
||||||
return EINVAL;
|
|
||||||
via8233_spdif_en = new_en;
|
|
||||||
|
|
||||||
dev = oidp->oid_arg1;
|
|
||||||
r = pci_read_config(dev, VIA_PCI_SPDIF, 1) & ~VIA_SPDIF_EN;
|
|
||||||
if (new_en)
|
|
||||||
r |= VIA_SPDIF_EN;
|
|
||||||
pci_write_config(dev, VIA_PCI_SPDIF, r, 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif /* SND_DYNSYSCTL */
|
|
||||||
|
|
||||||
static void
|
|
||||||
via_init_sysctls(device_t dev)
|
|
||||||
{
|
|
||||||
#ifdef SND_DYNSYSCTL
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = pci_read_config(dev, VIA_PCI_SPDIF, 1);
|
|
||||||
via8233_spdif_en = (r & VIA_SPDIF_EN) ? 1 : 0;
|
|
||||||
|
|
||||||
SYSCTL_ADD_PROC(snd_sysctl_tree(dev),
|
|
||||||
SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
|
||||||
OID_AUTO, "spdif_enabled",
|
|
||||||
CTLTYPE_INT | CTLFLAG_RW, dev, sizeof(dev),
|
|
||||||
sysctl_via8233_spdif_enable, "I",
|
|
||||||
"Enable S/PDIF output on primary playback channel");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
via_attach(device_t dev)
|
via_attach(device_t dev)
|
||||||
{
|
{
|
||||||
struct via_info *via = 0;
|
struct via_info *via = 0;
|
||||||
char status[SND_STATUSLEN];
|
char status[SND_STATUSLEN];
|
||||||
|
int i, via_dxs_disabled, via_dxs_src, via_dxs_chnum, via_sgd_chnum;
|
||||||
|
|
||||||
if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
|
if ((via = malloc(sizeof *via, M_DEVBUF, M_NOWAIT | M_ZERO)) == NULL) {
|
||||||
device_printf(dev, "cannot allocate softc\n");
|
device_printf(dev, "cannot allocate softc\n");
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
via->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
|
||||||
|
|
||||||
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
|
pci_set_powerstate(dev, PCI_POWERSTATE_D0);
|
||||||
pci_enable_busmaster(dev);
|
pci_enable_busmaster(dev);
|
||||||
@ -785,7 +872,7 @@ via_attach(device_t dev)
|
|||||||
via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
|
via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
|
||||||
RF_ACTIVE | RF_SHAREABLE);
|
RF_ACTIVE | RF_SHAREABLE);
|
||||||
if (!via->irq ||
|
if (!via->irq ||
|
||||||
snd_setup_intr(dev, via->irq, 0, via_intr, via, &via->ih)) {
|
snd_setup_intr(dev, via->irq, INTR_MPSAFE, via_intr, via, &via->ih)) {
|
||||||
device_printf(dev, "unable to map interrupt\n");
|
device_printf(dev, "unable to map interrupt\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -796,8 +883,8 @@ via_attach(device_t dev)
|
|||||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
|
/*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
/*flags*/0, /*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant, &via->parent_dmat) != 0) {
|
/*lockarg*/NULL, &via->parent_dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -813,8 +900,8 @@ via_attach(device_t dev)
|
|||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/NSEGS * sizeof(struct via_dma_op),
|
/*maxsize*/NSEGS * sizeof(struct via_dma_op),
|
||||||
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
/*flags*/0, /*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant, &via->sgd_dmat) != 0) {
|
/*lockarg*/NULL, &via->sgd_dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -850,28 +937,71 @@ via_attach(device_t dev)
|
|||||||
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
|
snprintf(status, SND_STATUSLEN, "at io 0x%lx irq %ld %s",
|
||||||
rman_get_start(via->reg), rman_get_start(via->irq),PCM_KLDSTRING(snd_via8233));
|
rman_get_start(via->reg), rman_get_start(via->irq),PCM_KLDSTRING(snd_via8233));
|
||||||
|
|
||||||
/* Register */
|
/*
|
||||||
|
* Decide whether DXS had to be disabled or not
|
||||||
|
*/
|
||||||
if (pci_get_revid(dev) == VIA8233_REV_ID_8233A) {
|
if (pci_get_revid(dev) == VIA8233_REV_ID_8233A) {
|
||||||
if (pcm_register(dev, via, NMSGDCHANS, 1)) goto bad;
|
|
||||||
/*
|
/*
|
||||||
* DXS channel is disabled. Reports from multiple users
|
* DXS channel is disabled. Reports from multiple users
|
||||||
* that it plays at half-speed. Do not see this behaviour
|
* that it plays at half-speed. Do not see this behaviour
|
||||||
* on available 8233C or when emulating 8233A register set
|
* on available 8233C or when emulating 8233A register set
|
||||||
* on 8233C (either with or without ac97 VRA).
|
* on 8233C (either with or without ac97 VRA).
|
||||||
pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
|
|
||||||
*/
|
*/
|
||||||
pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
|
via_dxs_disabled = 1;
|
||||||
pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
|
} else if (resource_int_value(device_get_name(dev),
|
||||||
|
device_get_unit(dev), "via_dxs_disabled",
|
||||||
|
&via_dxs_disabled) == 0)
|
||||||
|
via_dxs_disabled = (via_dxs_disabled > 0) ? 1 : 0;
|
||||||
|
else
|
||||||
|
via_dxs_disabled = 0;
|
||||||
|
|
||||||
|
if (via_dxs_disabled) {
|
||||||
|
via_dxs_chnum = 0;
|
||||||
|
via_sgd_chnum = 1;
|
||||||
} else {
|
} else {
|
||||||
int i;
|
if (resource_int_value(device_get_name(dev),
|
||||||
if (pcm_register(dev, via, NMSGDCHANS + NDXSCHANS, NWRCHANS)) goto bad;
|
device_get_unit(dev), "via_dxs_channels",
|
||||||
for (i = 0; i < NDXSCHANS; i++)
|
&via_dxs_chnum) != 0)
|
||||||
|
via_dxs_chnum = NDXSCHANS;
|
||||||
|
if (resource_int_value(device_get_name(dev),
|
||||||
|
device_get_unit(dev), "via_sgd_channels",
|
||||||
|
&via_sgd_chnum) != 0)
|
||||||
|
via_sgd_chnum = NMSGDCHANS;
|
||||||
|
}
|
||||||
|
if (via_dxs_chnum > NDXSCHANS)
|
||||||
|
via_dxs_chnum = NDXSCHANS;
|
||||||
|
else if (via_dxs_chnum < 0)
|
||||||
|
via_dxs_chnum = 0;
|
||||||
|
if (via_sgd_chnum > NMSGDCHANS)
|
||||||
|
via_sgd_chnum = NMSGDCHANS;
|
||||||
|
else if (via_sgd_chnum < 0)
|
||||||
|
via_sgd_chnum = 0;
|
||||||
|
if (via_dxs_chnum + via_sgd_chnum < 1) {
|
||||||
|
/* Minimalist ? */
|
||||||
|
via_dxs_chnum = 1;
|
||||||
|
via_sgd_chnum = 0;
|
||||||
|
}
|
||||||
|
if (via_dxs_chnum > 0 && resource_int_value(device_get_name(dev),
|
||||||
|
device_get_unit(dev), "via_dxs_src",
|
||||||
|
&via_dxs_src) == 0)
|
||||||
|
via->dxs_src = (via_dxs_src > 0) ? 1 : 0;
|
||||||
|
else
|
||||||
|
via->dxs_src = 0;
|
||||||
|
/* Register */
|
||||||
|
if (pcm_register(dev, via, via_dxs_chnum + via_sgd_chnum, NWRCHANS))
|
||||||
|
goto bad;
|
||||||
|
for (i = 0; i < via_dxs_chnum; i++)
|
||||||
pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
|
pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
|
||||||
|
for (i = 0; i < via_sgd_chnum; i++)
|
||||||
pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
|
pcm_addchan(dev, PCMDIR_PLAY, &via8233msgd_class, via);
|
||||||
for (i = 0; i < NWRCHANS; i++)
|
for (i = 0; i < NWRCHANS; i++)
|
||||||
pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
|
pcm_addchan(dev, PCMDIR_REC, &via8233wr_class, via);
|
||||||
|
if (via_dxs_chnum > 0)
|
||||||
via_init_sysctls(dev);
|
via_init_sysctls(dev);
|
||||||
}
|
device_printf(dev, "<VIA DXS %sabled: DXS%s %d / SGD %d / REC %d>\n",
|
||||||
|
(via_dxs_chnum > 0) ? "En" : "Dis",
|
||||||
|
(via->dxs_src) ? "(SRC)" : "",
|
||||||
|
via_dxs_chnum, via_sgd_chnum, NWRCHANS);
|
||||||
|
|
||||||
pcm_setstatus(dev, status);
|
pcm_setstatus(dev, status);
|
||||||
|
|
||||||
@ -884,6 +1014,7 @@ via_attach(device_t dev)
|
|||||||
if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
|
if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
|
||||||
if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
||||||
if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
|
if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
|
||||||
|
if (via->lock) snd_mtxfree(via->lock);
|
||||||
if (via) free(via, M_DEVBUF);
|
if (via) free(via, M_DEVBUF);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -904,6 +1035,7 @@ via_detach(device_t dev)
|
|||||||
bus_dma_tag_destroy(via->parent_dmat);
|
bus_dma_tag_destroy(via->parent_dmat);
|
||||||
bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
||||||
bus_dma_tag_destroy(via->sgd_dmat);
|
bus_dma_tag_destroy(via->sgd_dmat);
|
||||||
|
snd_mtxfree(via->lock);
|
||||||
free(via, M_DEVBUF);
|
free(via, M_DEVBUF);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,7 @@ struct via_info {
|
|||||||
struct via_chinfo pch, rch;
|
struct via_chinfo pch, rch;
|
||||||
struct via_dma_op *sgd_table;
|
struct via_dma_op *sgd_table;
|
||||||
u_int16_t codec_caps;
|
u_int16_t codec_caps;
|
||||||
|
struct mtx *lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u_int32_t via_fmt[] = {
|
static u_int32_t via_fmt[] = {
|
||||||
@ -98,7 +99,7 @@ static u_int32_t via_fmt[] = {
|
|||||||
static struct pcmchan_caps via_vracaps = {4000, 48000, via_fmt, 0};
|
static struct pcmchan_caps via_vracaps = {4000, 48000, via_fmt, 0};
|
||||||
static struct pcmchan_caps via_caps = {48000, 48000, via_fmt, 0};
|
static struct pcmchan_caps via_caps = {48000, 48000, via_fmt, 0};
|
||||||
|
|
||||||
static u_int32_t
|
static __inline u_int32_t
|
||||||
via_rd(struct via_info *via, int regno, int size)
|
via_rd(struct via_info *via, int regno, int size)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -115,7 +116,7 @@ via_rd(struct via_info *via, int regno, int size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static __inline void
|
||||||
via_wr(struct via_info *via, int regno, u_int32_t data, int size)
|
via_wr(struct via_info *via, int regno, u_int32_t data, int size)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -244,6 +245,7 @@ viachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
|
|||||||
struct via_info *via = devinfo;
|
struct via_info *via = devinfo;
|
||||||
struct via_chinfo *ch;
|
struct via_chinfo *ch;
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
if (dir == PCMDIR_PLAY) {
|
if (dir == PCMDIR_PLAY) {
|
||||||
ch = &via->pch;
|
ch = &via->pch;
|
||||||
ch->base = VIA_PLAY_DMAOPS_BASE;
|
ch->base = VIA_PLAY_DMAOPS_BASE;
|
||||||
@ -266,9 +268,11 @@ viachan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
|
|||||||
ch->channel = c;
|
ch->channel = c;
|
||||||
ch->buffer = b;
|
ch->buffer = b;
|
||||||
ch->dir = dir;
|
ch->dir = dir;
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
if (sndbuf_alloc(ch->buffer, via->parent_dmat, via->bufsz) != 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return ch;
|
return ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,10 +290,12 @@ viachan_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
mode_set |= VIA_RPMODE_16BIT;
|
mode_set |= VIA_RPMODE_16BIT;
|
||||||
|
|
||||||
DEB(printf("set format: dir = %d, format=%x\n", ch->dir, format));
|
DEB(printf("set format: dir = %d, format=%x\n", ch->dir, format));
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
mode = via_rd(via, ch->mode, 1);
|
mode = via_rd(via, ch->mode, 1);
|
||||||
mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
|
mode &= ~(VIA_RPMODE_16BIT | VIA_RPMODE_STEREO);
|
||||||
mode |= mode_set;
|
mode |= mode_set;
|
||||||
via_wr(via, ch->mode, mode, 1);
|
via_wr(via, ch->mode, mode, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -342,12 +348,14 @@ viachan_trigger(kobj_t obj, void *data, int go)
|
|||||||
ado = ch->sgd_table;
|
ado = ch->sgd_table;
|
||||||
DEB(printf("ado located at va=%p pa=%x\n", ado, sgd_addr));
|
DEB(printf("ado located at va=%p pa=%x\n", ado, sgd_addr));
|
||||||
|
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
if (go == PCMTRIG_START) {
|
if (go == PCMTRIG_START) {
|
||||||
via_buildsgdt(ch);
|
via_buildsgdt(ch);
|
||||||
via_wr(via, ch->base, sgd_addr, 4);
|
via_wr(via, ch->base, sgd_addr, 4);
|
||||||
via_wr(via, ch->ctrl, VIA_RPCTRL_START, 1);
|
via_wr(via, ch->ctrl, VIA_RPCTRL_START, 1);
|
||||||
} else
|
} else
|
||||||
via_wr(via, ch->ctrl, VIA_RPCTRL_TERMINATE, 1);
|
via_wr(via, ch->ctrl, VIA_RPCTRL_TERMINATE, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
DEB(printf("viachan_trigger: go=%d\n", go));
|
DEB(printf("viachan_trigger: go=%d\n", go));
|
||||||
return 0;
|
return 0;
|
||||||
@ -363,11 +371,13 @@ viachan_getptr(kobj_t obj, void *data)
|
|||||||
int ptr, base, base1, len, seg;
|
int ptr, base, base1, len, seg;
|
||||||
|
|
||||||
ado = ch->sgd_table;
|
ado = ch->sgd_table;
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
base1 = via_rd(via, ch->base, 4);
|
base1 = via_rd(via, ch->base, 4);
|
||||||
len = via_rd(via, ch->count, 4);
|
len = via_rd(via, ch->count, 4);
|
||||||
base = via_rd(via, ch->base, 4);
|
base = via_rd(via, ch->base, 4);
|
||||||
if (base != base1) /* Avoid race hazard */
|
if (base != base1) /* Avoid race hazard */
|
||||||
len = via_rd(via, ch->count, 4);
|
len = via_rd(via, ch->count, 4);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
|
|
||||||
DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
|
DEB(printf("viachan_getptr: len / base = %x / %x\n", len, base));
|
||||||
|
|
||||||
@ -417,22 +427,25 @@ static void
|
|||||||
via_intr(void *p)
|
via_intr(void *p)
|
||||||
{
|
{
|
||||||
struct via_info *via = p;
|
struct via_info *via = p;
|
||||||
int st;
|
|
||||||
|
|
||||||
/* DEB(printf("viachan_intr\n")); */
|
/* DEB(printf("viachan_intr\n")); */
|
||||||
/* Read channel */
|
/* Read channel */
|
||||||
st = via_rd(via, VIA_PLAY_STAT, 1);
|
snd_mtxlock(via->lock);
|
||||||
if (st & VIA_RPSTAT_INTR) {
|
if (via_rd(via, VIA_PLAY_STAT, 1) & VIA_RPSTAT_INTR) {
|
||||||
via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1);
|
via_wr(via, VIA_PLAY_STAT, VIA_RPSTAT_INTR, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
chn_intr(via->pch.channel);
|
chn_intr(via->pch.channel);
|
||||||
|
snd_mtxlock(via->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write channel */
|
/* Write channel */
|
||||||
st = via_rd(via, VIA_RECORD_STAT, 1);
|
if (via_rd(via, VIA_RECORD_STAT, 1) & VIA_RPSTAT_INTR) {
|
||||||
if (st & VIA_RPSTAT_INTR) {
|
|
||||||
via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1);
|
via_wr(via, VIA_RECORD_STAT, VIA_RPSTAT_INTR, 1);
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
chn_intr(via->rch.channel);
|
chn_intr(via->rch.channel);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
snd_mtxunlock(via->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -468,6 +481,7 @@ via_attach(device_t dev)
|
|||||||
device_printf(dev, "cannot allocate softc\n");
|
device_printf(dev, "cannot allocate softc\n");
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
via->lock = snd_mtxcreate(device_get_nameunit(dev), "sound softc");
|
||||||
|
|
||||||
/* Get resources */
|
/* Get resources */
|
||||||
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
data = pci_read_config(dev, PCIR_COMMAND, 2);
|
||||||
@ -521,7 +535,7 @@ via_attach(device_t dev)
|
|||||||
via->irqid = 0;
|
via->irqid = 0;
|
||||||
via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
|
via->irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &via->irqid,
|
||||||
RF_ACTIVE | RF_SHAREABLE);
|
RF_ACTIVE | RF_SHAREABLE);
|
||||||
if (!via->irq || snd_setup_intr(dev, via->irq, 0, via_intr, via, &via->ih)) {
|
if (!via->irq || snd_setup_intr(dev, via->irq, INTR_MPSAFE, via_intr, via, &via->ih)) {
|
||||||
device_printf(dev, "unable to map interrupt\n");
|
device_printf(dev, "unable to map interrupt\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -546,8 +560,8 @@ via_attach(device_t dev)
|
|||||||
/*highaddr*/BUS_SPACE_MAXADDR,
|
/*highaddr*/BUS_SPACE_MAXADDR,
|
||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
|
/*maxsize*/via->bufsz, /*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
/*flags*/0, /*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant, &via->parent_dmat) != 0) {
|
/*lockarg*/NULL, &via->parent_dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -563,8 +577,8 @@ via_attach(device_t dev)
|
|||||||
/*filter*/NULL, /*filterarg*/NULL,
|
/*filter*/NULL, /*filterarg*/NULL,
|
||||||
/*maxsize*/NSEGS * sizeof(struct via_dma_op),
|
/*maxsize*/NSEGS * sizeof(struct via_dma_op),
|
||||||
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
/*nsegments*/1, /*maxsegz*/0x3ffff,
|
||||||
/*flags*/0, /*lockfunc*/busdma_lock_mutex,
|
/*flags*/0, /*lockfunc*/NULL,
|
||||||
/*lockarg*/&Giant, &via->sgd_dmat) != 0) {
|
/*lockarg*/NULL, &via->sgd_dmat) != 0) {
|
||||||
device_printf(dev, "unable to create dma tag\n");
|
device_printf(dev, "unable to create dma tag\n");
|
||||||
goto bad;
|
goto bad;
|
||||||
}
|
}
|
||||||
@ -594,6 +608,7 @@ via_attach(device_t dev)
|
|||||||
if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
|
if (via->parent_dmat) bus_dma_tag_destroy(via->parent_dmat);
|
||||||
if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
if (via->sgd_dmamap) bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
||||||
if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
|
if (via->sgd_dmat) bus_dma_tag_destroy(via->sgd_dmat);
|
||||||
|
if (via->lock) snd_mtxfree(via->lock);
|
||||||
if (via) free(via, M_DEVBUF);
|
if (via) free(via, M_DEVBUF);
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -615,6 +630,7 @@ via_detach(device_t dev)
|
|||||||
bus_dma_tag_destroy(via->parent_dmat);
|
bus_dma_tag_destroy(via->parent_dmat);
|
||||||
bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
bus_dmamap_unload(via->sgd_dmat, via->sgd_dmamap);
|
||||||
bus_dma_tag_destroy(via->sgd_dmat);
|
bus_dma_tag_destroy(via->sgd_dmat);
|
||||||
|
snd_mtxfree(via->lock);
|
||||||
free(via, M_DEVBUF);
|
free(via, M_DEVBUF);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,8 @@ static const struct ac97mixtable_entry ac97mixtable_default[32] = {
|
|||||||
[SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
|
[SOUND_MIXER_LINE] = { AC97_MIX_LINE, 5, 0, 1, 1, 5, 0, 1 },
|
||||||
[SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
|
[SOUND_MIXER_PHONEIN] = { AC97_MIX_PHONE, 5, 0, 0, 1, 8, 0, 0 },
|
||||||
[SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
|
[SOUND_MIXER_MIC] = { AC97_MIX_MIC, 5, 0, 0, 1, 1, 1, 1 },
|
||||||
#if 0
|
|
||||||
/* use igain for the mic 20dB boost */
|
/* use igain for the mic 20dB boost */
|
||||||
[SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
|
[SOUND_MIXER_IGAIN] = { -AC97_MIX_MIC, 1, 6, 0, 0, 0, 1, 1 },
|
||||||
#endif
|
|
||||||
[SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
|
[SOUND_MIXER_CD] = { AC97_MIX_CD, 5, 0, 1, 1, 2, 0, 1 },
|
||||||
[SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
|
[SOUND_MIXER_LINE1] = { AC97_MIX_AUX, 5, 0, 1, 1, 4, 0, 0 },
|
||||||
[SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
|
[SOUND_MIXER_VIDEO] = { AC97_MIX_VIDEO, 5, 0, 1, 1, 3, 0, 0 },
|
||||||
@ -118,6 +116,11 @@ static const struct ac97_vendorid ac97vendorid[] = {
|
|||||||
{ 0x57454300, "Winbond" },
|
{ 0x57454300, "Winbond" },
|
||||||
{ 0x574d4c00, "Wolfson" },
|
{ 0x574d4c00, "Wolfson" },
|
||||||
{ 0x594d4800, "Yamaha" },
|
{ 0x594d4800, "Yamaha" },
|
||||||
|
/*
|
||||||
|
* XXX This is a fluke, really! The real vendor
|
||||||
|
* should be SigmaTel, not this! This should be
|
||||||
|
* removed someday!
|
||||||
|
*/
|
||||||
{ 0x01408300, "Creative" },
|
{ 0x01408300, "Creative" },
|
||||||
{ 0x00000000, NULL }
|
{ 0x00000000, NULL }
|
||||||
};
|
};
|
||||||
@ -145,7 +148,9 @@ static struct ac97_codecid ac97codecid[] = {
|
|||||||
{ 0x414c4710, 0x0f, 0, "ALC200", 0 },
|
{ 0x414c4710, 0x0f, 0, "ALC200", 0 },
|
||||||
{ 0x414c4740, 0x0f, 0, "ALC202", 0 },
|
{ 0x414c4740, 0x0f, 0, "ALC202", 0 },
|
||||||
{ 0x414c4720, 0x0f, 0, "ALC650", 0 },
|
{ 0x414c4720, 0x0f, 0, "ALC650", 0 },
|
||||||
|
{ 0x414c4752, 0x0f, 0, "ALC250", 0 },
|
||||||
{ 0x414c4760, 0x0f, 0, "ALC655", 0 },
|
{ 0x414c4760, 0x0f, 0, "ALC655", 0 },
|
||||||
|
{ 0x414c4770, 0x0f, 0, "ALC203", 0 },
|
||||||
{ 0x414c4780, 0x0f, 0, "ALC658", 0 },
|
{ 0x414c4780, 0x0f, 0, "ALC658", 0 },
|
||||||
{ 0x414c4790, 0x0f, 0, "ALC850", 0 },
|
{ 0x414c4790, 0x0f, 0, "ALC850", 0 },
|
||||||
{ 0x43525900, 0x07, 0, "CS4297", 0 },
|
{ 0x43525900, 0x07, 0, "CS4297", 0 },
|
||||||
@ -156,10 +161,14 @@ static struct ac97_codecid ac97codecid[] = {
|
|||||||
{ 0x43525940, 0x07, 0, "CS4201", 0 },
|
{ 0x43525940, 0x07, 0, "CS4201", 0 },
|
||||||
{ 0x43525958, 0x07, 0, "CS4205", 0 },
|
{ 0x43525958, 0x07, 0, "CS4205", 0 },
|
||||||
{ 0x43525960, 0x07, 0, "CS4291A", 0 },
|
{ 0x43525960, 0x07, 0, "CS4291A", 0 },
|
||||||
{ 0x434d4961, 0x00, 0, "CMI9739", 0 },
|
{ 0x434d4961, 0x00, 0, "CMI9739", cmi9739_patch },
|
||||||
{ 0x434d4941, 0x00, 0, "CMI9738", 0 },
|
{ 0x434d4941, 0x00, 0, "CMI9738", 0 },
|
||||||
|
{ 0x434d4978, 0x00, 0, "CMI9761", 0 },
|
||||||
|
{ 0x434d4982, 0x00, 0, "CMI9761", 0 },
|
||||||
|
{ 0x434d4983, 0x00, 0, "CMI9761", 0 },
|
||||||
{ 0x43585421, 0x00, 0, "HSD11246", 0 },
|
{ 0x43585421, 0x00, 0, "HSD11246", 0 },
|
||||||
{ 0x43585428, 0x07, 0, "CX20468", 0 },
|
{ 0x43585428, 0x07, 0, "CX20468", 0 },
|
||||||
|
{ 0x43585430, 0x00, 0, "CX20468-21", 0 },
|
||||||
{ 0x44543000, 0x00, 0, "DT0398", 0 },
|
{ 0x44543000, 0x00, 0, "DT0398", 0 },
|
||||||
{ 0x454d4323, 0x00, 0, "EM28023", 0 },
|
{ 0x454d4323, 0x00, 0, "EM28023", 0 },
|
||||||
{ 0x454d4328, 0x00, 0, "EM28028", 0 },
|
{ 0x454d4328, 0x00, 0, "EM28028", 0 },
|
||||||
@ -192,6 +201,7 @@ static struct ac97_codecid ac97codecid[] = {
|
|||||||
{ 0x83847658, 0x00, 0, "STAC9758/59", 0 },
|
{ 0x83847658, 0x00, 0, "STAC9758/59", 0 },
|
||||||
{ 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
|
{ 0x83847660, 0x00, 0, "STAC9760/61", 0 }, /* Extrapolated */
|
||||||
{ 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
|
{ 0x83847662, 0x00, 0, "STAC9762/63", 0 }, /* Extrapolated */
|
||||||
|
{ 0x83847666, 0x00, 0, "STAC9766/67", 0 },
|
||||||
{ 0x53494c22, 0x00, 0, "Si3036", 0 },
|
{ 0x53494c22, 0x00, 0, "Si3036", 0 },
|
||||||
{ 0x53494c23, 0x00, 0, "Si3038", 0 },
|
{ 0x53494c23, 0x00, 0, "Si3038", 0 },
|
||||||
{ 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
|
{ 0x54524103, 0x00, 0, "TR28023", 0 }, /* Extrapolated */
|
||||||
@ -201,6 +211,7 @@ static struct ac97_codecid ac97codecid[] = {
|
|||||||
{ 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
|
{ 0x54524e03, 0x07, 0, "TLV320AIC27", 0 },
|
||||||
{ 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
|
{ 0x54584e20, 0x00, 0, "TLC320AD90", 0 },
|
||||||
{ 0x56494161, 0x00, 0, "VIA1612A", 0 },
|
{ 0x56494161, 0x00, 0, "VIA1612A", 0 },
|
||||||
|
{ 0x56494170, 0x00, 0, "VIA1617A", 0 },
|
||||||
{ 0x574d4c00, 0x00, 0, "WM9701A", 0 },
|
{ 0x574d4c00, 0x00, 0, "WM9701A", 0 },
|
||||||
{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
|
{ 0x574d4c03, 0x00, 0, "WM9703/4/7/8", 0 },
|
||||||
{ 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
|
{ 0x574d4c04, 0x00, 0, "WM9704Q", 0 },
|
||||||
@ -211,6 +222,11 @@ static struct ac97_codecid ac97codecid[] = {
|
|||||||
{ 0x594d4800, 0x00, 0, "YMF743", 0 },
|
{ 0x594d4800, 0x00, 0, "YMF743", 0 },
|
||||||
{ 0x594d4802, 0x00, 0, "YMF752", 0 },
|
{ 0x594d4802, 0x00, 0, "YMF752", 0 },
|
||||||
{ 0x594d4803, 0x00, 0, "YMF753", 0 },
|
{ 0x594d4803, 0x00, 0, "YMF753", 0 },
|
||||||
|
/*
|
||||||
|
* XXX This is a fluke, really! The real codec
|
||||||
|
* should be STAC9704, not this! This should be
|
||||||
|
* removed someday!
|
||||||
|
*/
|
||||||
{ 0x01408384, 0x00, 0, "EV1938", 0 },
|
{ 0x01408384, 0x00, 0, "EV1938", 0 },
|
||||||
{ 0, 0, 0, NULL, 0 }
|
{ 0, 0, 0, NULL, 0 }
|
||||||
};
|
};
|
||||||
@ -283,6 +299,21 @@ static char *ac97extfeature[] = {
|
|||||||
u_int16_t
|
u_int16_t
|
||||||
ac97_rdcd(struct ac97_info *codec, int reg)
|
ac97_rdcd(struct ac97_info *codec, int reg)
|
||||||
{
|
{
|
||||||
|
if (codec->flags & AC97_F_RDCD_BUG) {
|
||||||
|
u_int16_t i[2], j = 100;
|
||||||
|
|
||||||
|
i[0] = AC97_READ(codec->methods, codec->devinfo, reg);
|
||||||
|
i[1] = AC97_READ(codec->methods, codec->devinfo, reg);
|
||||||
|
while (i[0] != i[1] && j)
|
||||||
|
i[j-- & 1] = AC97_READ(codec->methods, codec->devinfo, reg);
|
||||||
|
#if 0
|
||||||
|
if (j < 100) {
|
||||||
|
device_printf(codec->dev, "%s(): Inconsistent register value at"
|
||||||
|
" 0x%08x (retry: %d)\n", __func__, reg, 100 - j);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return i[!(j & 1)];
|
||||||
|
}
|
||||||
return AC97_READ(codec->methods, codec->devinfo, reg);
|
return AC97_READ(codec->methods, codec->devinfo, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -452,14 +483,16 @@ ac97_setmixer(struct ac97_info *codec, unsigned channel, unsigned left, unsigned
|
|||||||
*/
|
*/
|
||||||
snd_mtxlock(codec->lock);
|
snd_mtxlock(codec->lock);
|
||||||
if (e->mask) {
|
if (e->mask) {
|
||||||
int cur = ac97_rdcd(codec, e->reg);
|
int cur = ac97_rdcd(codec, reg);
|
||||||
val |= cur & ~(mask);
|
val |= cur & ~(mask);
|
||||||
}
|
}
|
||||||
ac97_wrcd(codec, reg, val);
|
ac97_wrcd(codec, reg, val);
|
||||||
snd_mtxunlock(codec->lock);
|
snd_mtxunlock(codec->lock);
|
||||||
return left | (right << 8);
|
return left | (right << 8);
|
||||||
} else {
|
} else {
|
||||||
/* printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable); */
|
#if 0
|
||||||
|
printf("ac97_setmixer: reg=%d, bits=%d, enable=%d\n", e->reg, e->bits, e->enable);
|
||||||
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -511,6 +544,40 @@ ac97_fix_tone(struct ac97_info *codec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ac97_fix_volume(struct ac97_info *codec)
|
||||||
|
{
|
||||||
|
struct snddev_info *d = device_get_softc(codec->dev);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* XXX For the sake of debugging purposes */
|
||||||
|
ac97_wrcd(codec, AC97_MIX_PCM, 0);
|
||||||
|
bzero(&codec->mix[SOUND_MIXER_PCM],
|
||||||
|
sizeof(codec->mix[SOUND_MIXER_PCM]));
|
||||||
|
codec->flags |= AC97_F_SOFTVOL;
|
||||||
|
if (d)
|
||||||
|
d->flags |= SD_F_SOFTVOL;
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
switch (codec->id) {
|
||||||
|
case 0x434d4941: /* CMI9738 */
|
||||||
|
case 0x434d4961: /* CMI9739 */
|
||||||
|
case 0x434d4978: /* CMI9761 */
|
||||||
|
case 0x434d4982: /* CMI9761 */
|
||||||
|
case 0x434d4983: /* CMI9761 */
|
||||||
|
ac97_wrcd(codec, AC97_MIX_PCM, 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bzero(&codec->mix[SOUND_MIXER_PCM],
|
||||||
|
sizeof(codec->mix[SOUND_MIXER_PCM]));
|
||||||
|
codec->flags |= AC97_F_SOFTVOL;
|
||||||
|
if (d)
|
||||||
|
d->flags |= SD_F_SOFTVOL;
|
||||||
|
}
|
||||||
|
|
||||||
static const char*
|
static const char*
|
||||||
ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
|
ac97_hw_desc(u_int32_t id, const char* vname, const char* cname, char* buf)
|
||||||
{
|
{
|
||||||
@ -536,8 +603,9 @@ ac97_initmixer(struct ac97_info *codec)
|
|||||||
const char *cname, *vname;
|
const char *cname, *vname;
|
||||||
char desc[80];
|
char desc[80];
|
||||||
u_int8_t model, step;
|
u_int8_t model, step;
|
||||||
unsigned i, j, k, old;
|
unsigned i, j, k, bit, old;
|
||||||
u_int32_t id;
|
u_int32_t id;
|
||||||
|
int reg;
|
||||||
|
|
||||||
snd_mtxlock(codec->lock);
|
snd_mtxlock(codec->lock);
|
||||||
codec->count = AC97_INIT(codec->methods, codec->devinfo);
|
codec->count = AC97_INIT(codec->methods, codec->devinfo);
|
||||||
@ -552,6 +620,16 @@ ac97_initmixer(struct ac97_info *codec)
|
|||||||
ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
|
ac97_wrcd(codec, AC97_REG_POWER, (codec->flags & AC97_F_EAPD_INV)? 0x8000 : 0x0000);
|
||||||
|
|
||||||
i = ac97_rdcd(codec, AC97_REG_RESET);
|
i = ac97_rdcd(codec, AC97_REG_RESET);
|
||||||
|
j = ac97_rdcd(codec, AC97_REG_RESET);
|
||||||
|
/*
|
||||||
|
* Let see if this codec can return consistent value.
|
||||||
|
* If not, turn on aggressive read workaround
|
||||||
|
* (STAC9704 comes in mind).
|
||||||
|
*/
|
||||||
|
if (i != j) {
|
||||||
|
codec->flags |= AC97_F_RDCD_BUG;
|
||||||
|
i = ac97_rdcd(codec, AC97_REG_RESET);
|
||||||
|
}
|
||||||
codec->caps = i & 0x03ff;
|
codec->caps = i & 0x03ff;
|
||||||
codec->se = (i & 0x7c00) >> 10;
|
codec->se = (i & 0x7c00) >> 10;
|
||||||
|
|
||||||
@ -605,27 +683,75 @@ ac97_initmixer(struct ac97_info *codec)
|
|||||||
}
|
}
|
||||||
ac97_fix_auxout(codec);
|
ac97_fix_auxout(codec);
|
||||||
ac97_fix_tone(codec);
|
ac97_fix_tone(codec);
|
||||||
|
ac97_fix_volume(codec);
|
||||||
if (codec_patch)
|
if (codec_patch)
|
||||||
codec_patch(codec);
|
codec_patch(codec);
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
k = codec->noext? codec->mix[i].enable : 1;
|
k = codec->noext? codec->mix[i].enable : 1;
|
||||||
if (k && (codec->mix[i].reg > 0)) {
|
reg = codec->mix[i].reg;
|
||||||
old = ac97_rdcd(codec, codec->mix[i].reg);
|
if (reg < 0)
|
||||||
ac97_wrcd(codec, codec->mix[i].reg, 0x3f);
|
reg = -reg;
|
||||||
j = ac97_rdcd(codec, codec->mix[i].reg);
|
if (k && reg) {
|
||||||
ac97_wrcd(codec, codec->mix[i].reg, old);
|
j = old = ac97_rdcd(codec, reg);
|
||||||
codec->mix[i].enable = (j != 0 && j != old)? 1 : 0;
|
/*
|
||||||
for (k = 1; j & (1 << k); k++);
|
* Test for mute bit (except for AC97_MIX_TONE,
|
||||||
codec->mix[i].bits = j? k - codec->mix[i].ofs : 0;
|
* where we simply assume it as available).
|
||||||
|
*/
|
||||||
|
if (codec->mix[i].mute) {
|
||||||
|
ac97_wrcd(codec, reg, j | 0x8000);
|
||||||
|
j = ac97_rdcd(codec, reg);
|
||||||
|
} else
|
||||||
|
j |= 0x8000;
|
||||||
|
if ((j & 0x8000)) {
|
||||||
|
/*
|
||||||
|
* Test whether the control width should be
|
||||||
|
* 4, 5 or 6 bit. For 5bit register, we should
|
||||||
|
* test it whether it's really 5 or 6bit. Leave
|
||||||
|
* 4bit register alone, because sometimes an
|
||||||
|
* attempt to write past 4th bit may cause
|
||||||
|
* incorrect result especially for AC97_MIX_BEEP
|
||||||
|
* (ac97 2.3).
|
||||||
|
*/
|
||||||
|
bit = codec->mix[i].bits;
|
||||||
|
if (bit == 5)
|
||||||
|
bit++;
|
||||||
|
j = ((1 << bit) - 1) << codec->mix[i].ofs;
|
||||||
|
ac97_wrcd(codec, reg,
|
||||||
|
j | (codec->mix[i].mute ? 0x8000 : 0));
|
||||||
|
k = ac97_rdcd(codec, reg) & j;
|
||||||
|
k >>= codec->mix[i].ofs;
|
||||||
|
if (reg == AC97_MIX_TONE &&
|
||||||
|
((k & 0x0001) == 0x0000))
|
||||||
|
k >>= 1;
|
||||||
|
for (j = 0; k >> j; j++)
|
||||||
|
;
|
||||||
|
if (j != 0) {
|
||||||
|
#if 0
|
||||||
|
device_printf(codec->dev, "%2d: [ac97_rdcd() = %d] [Testbit = %d] %d -> %d\n",
|
||||||
|
i, k, bit, codec->mix[i].bits, j);
|
||||||
|
#endif
|
||||||
|
codec->mix[i].enable = 1;
|
||||||
|
codec->mix[i].bits = j;
|
||||||
|
} else
|
||||||
|
codec->mix[i].enable = 0;
|
||||||
|
} else
|
||||||
|
codec->mix[i].enable = 0;
|
||||||
|
ac97_wrcd(codec, reg, old);
|
||||||
}
|
}
|
||||||
/* printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits); */
|
#if 0
|
||||||
|
printf("mixch %d, en=%d, b=%d\n", i, codec->mix[i].enable, codec->mix[i].bits);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
device_printf(codec->dev, "<%s>\n",
|
device_printf(codec->dev, "<%s>\n",
|
||||||
ac97_hw_desc(codec->id, vname, cname, desc));
|
ac97_hw_desc(codec->id, vname, cname, desc));
|
||||||
|
|
||||||
if (bootverbose) {
|
if (bootverbose) {
|
||||||
|
if (codec->flags & AC97_F_RDCD_BUG)
|
||||||
|
device_printf(codec->dev, "Buggy AC97 Codec: aggressive ac97_rdcd() workaround enabled\n");
|
||||||
|
if (codec->flags & AC97_F_SOFTVOL)
|
||||||
|
device_printf(codec->dev, "Soft PCM volume\n");
|
||||||
device_printf(codec->dev, "Codec features ");
|
device_printf(codec->dev, "Codec features ");
|
||||||
for (i = j = 0; i < 10; i++)
|
for (i = j = 0; i < 10; i++)
|
||||||
if (codec->caps & (1 << i))
|
if (codec->caps & (1 << i))
|
||||||
@ -645,8 +771,16 @@ ac97_initmixer(struct ac97_info *codec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0)
|
i = 0;
|
||||||
|
while ((ac97_rdcd(codec, AC97_REG_POWER) & 2) == 0) {
|
||||||
|
if (++i == 100) {
|
||||||
device_printf(codec->dev, "ac97 codec reports dac not ready\n");
|
device_printf(codec->dev, "ac97 codec reports dac not ready\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DELAY(1000);
|
||||||
|
}
|
||||||
|
if (bootverbose)
|
||||||
|
device_printf(codec->dev, "ac97 codec dac ready count: %d\n", i);
|
||||||
snd_mtxunlock(codec->lock);
|
snd_mtxunlock(codec->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
#define AC97_REG_ID2 0x7e
|
#define AC97_REG_ID2 0x7e
|
||||||
|
|
||||||
#define AC97_F_EAPD_INV 0x00000001
|
#define AC97_F_EAPD_INV 0x00000001
|
||||||
|
#define AC97_F_RDCD_BUG 0x00000002
|
||||||
|
#define AC97_F_SOFTVOL 0x00000004
|
||||||
|
|
||||||
#define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
|
#define AC97_DECLARE(name) static DEFINE_CLASS(name, name ## _methods, sizeof(struct kobj))
|
||||||
#define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class)
|
#define AC97_CREATE(dev, devinfo, cls) ac97_create(dev, devinfo, &cls ## _class)
|
||||||
|
@ -46,3 +46,13 @@ void ad198x_patch(struct ac97_info* codec)
|
|||||||
ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0420);
|
ac97_wrcd(codec, 0x76, ac97_rdcd(codec, 0x76) | 0x0420);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cmi9739_patch(struct ac97_info* codec)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Few laptops (notably ASUS W1000N) need extra register
|
||||||
|
* initialization to power up the internal speakers.
|
||||||
|
*/
|
||||||
|
ac97_wrcd(codec, AC97_REG_POWER, 0x000f);
|
||||||
|
ac97_wrcd(codec, AC97_MIXEXT_CLFE, 0x0000);
|
||||||
|
ac97_wrcd(codec, 0x64, 0x7110);
|
||||||
|
}
|
||||||
|
@ -29,3 +29,4 @@ typedef void (*ac97_patch)(struct ac97_info*);
|
|||||||
|
|
||||||
void ad1886_patch(struct ac97_info*);
|
void ad1886_patch(struct ac97_info*);
|
||||||
void ad198x_patch(struct ac97_info*);
|
void ad198x_patch(struct ac97_info*);
|
||||||
|
void cmi9739_patch(struct ac97_info*);
|
||||||
|
@ -286,8 +286,12 @@ sndbuf_setfmt(struct snd_dbuf *b, u_int32_t fmt)
|
|||||||
b->fmt = fmt;
|
b->fmt = fmt;
|
||||||
b->bps = 1;
|
b->bps = 1;
|
||||||
b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0;
|
b->bps <<= (b->fmt & AFMT_STEREO)? 1 : 0;
|
||||||
b->bps <<= (b->fmt & AFMT_16BIT)? 1 : 0;
|
if (b->fmt & AFMT_16BIT)
|
||||||
b->bps <<= (b->fmt & AFMT_32BIT)? 2 : 0;
|
b->bps <<= 1;
|
||||||
|
else if (b->fmt & AFMT_24BIT)
|
||||||
|
b->bps *= 3;
|
||||||
|
else if (b->fmt & AFMT_32BIT)
|
||||||
|
b->bps <<= 2;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,9 @@ chn_polltrigger(struct pcm_channel *c)
|
|||||||
return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
|
return (sndbuf_getblocks(bs) > sndbuf_getprevblocks(bs))? 1 : 0;
|
||||||
} else {
|
} else {
|
||||||
amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
|
amt = (c->direction == PCMDIR_PLAY)? sndbuf_getfree(bs) : sndbuf_getready(bs);
|
||||||
|
#if 0
|
||||||
lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
|
lim = (c->flags & CHN_F_HAS_SIZE)? sndbuf_getblksz(bs) : 1;
|
||||||
|
#endif
|
||||||
lim = 1;
|
lim = 1;
|
||||||
return (amt >= lim)? 1 : 0;
|
return (amt >= lim)? 1 : 0;
|
||||||
}
|
}
|
||||||
@ -163,7 +165,7 @@ chn_sleep(struct pcm_channel *c, char *str, int timeout)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* chn_dmaupdate() tracks the status of a dma transfer,
|
* chn_dmaupdate() tracks the status of a dma transfer,
|
||||||
* updating pointers. It must be called at spltty().
|
* updating pointers.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
@ -227,11 +229,13 @@ chn_wrfeed(struct pcm_channel *c)
|
|||||||
unsigned int ret, amt;
|
unsigned int ret, amt;
|
||||||
|
|
||||||
CHN_LOCKASSERT(c);
|
CHN_LOCKASSERT(c);
|
||||||
/* DEB(
|
#if 0
|
||||||
|
DEB(
|
||||||
if (c->flags & CHN_F_CLOSING) {
|
if (c->flags & CHN_F_CLOSING) {
|
||||||
sndbuf_dump(b, "b", 0x02);
|
sndbuf_dump(b, "b", 0x02);
|
||||||
sndbuf_dump(bs, "bs", 0x02);
|
sndbuf_dump(bs, "bs", 0x02);
|
||||||
}) */
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
if (c->flags & CHN_F_MAPPED)
|
if (c->flags & CHN_F_MAPPED)
|
||||||
sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
|
sndbuf_acquire(bs, NULL, sndbuf_getfree(bs));
|
||||||
@ -240,10 +244,14 @@ chn_wrfeed(struct pcm_channel *c)
|
|||||||
KASSERT(amt <= sndbuf_getsize(bs),
|
KASSERT(amt <= sndbuf_getsize(bs),
|
||||||
("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name,
|
("%s(%s): amt %d > source size %d, flags 0x%x", __func__, c->name,
|
||||||
amt, sndbuf_getsize(bs), c->flags));
|
amt, sndbuf_getsize(bs), c->flags));
|
||||||
if (sndbuf_getready(bs) < amt)
|
|
||||||
c->xruns++;
|
|
||||||
|
|
||||||
ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
|
ret = (amt > 0) ? sndbuf_feed(bs, b, c, c->feeder, amt) : ENOSPC;
|
||||||
|
/*
|
||||||
|
* Possible xruns. There should be no empty space left in buffer.
|
||||||
|
*/
|
||||||
|
if (sndbuf_getfree(b) > 0)
|
||||||
|
c->xruns++;
|
||||||
|
|
||||||
if (ret == 0 && sndbuf_getfree(b) < amt)
|
if (ret == 0 && sndbuf_getfree(b) < amt)
|
||||||
chn_wakeup(c);
|
chn_wakeup(c);
|
||||||
|
|
||||||
@ -359,13 +367,17 @@ chn_rddump(struct pcm_channel *c, unsigned int cnt)
|
|||||||
struct snd_dbuf *b = c->bufhard;
|
struct snd_dbuf *b = c->bufhard;
|
||||||
|
|
||||||
CHN_LOCKASSERT(c);
|
CHN_LOCKASSERT(c);
|
||||||
|
#if 0
|
||||||
|
static uint32_t kk = 0;
|
||||||
|
printf("%u: dumping %d bytes\n", ++kk, cnt);
|
||||||
|
#endif
|
||||||
|
c->xruns++;
|
||||||
sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
|
sndbuf_setxrun(b, sndbuf_getxrun(b) + cnt);
|
||||||
return sndbuf_dispose(b, NULL, cnt);
|
return sndbuf_dispose(b, NULL, cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Feed new data from the read buffer. Can be called in the bottom half.
|
* Feed new data from the read buffer. Can be called in the bottom half.
|
||||||
* Hence must be called at spltty.
|
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
chn_rdfeed(struct pcm_channel *c)
|
chn_rdfeed(struct pcm_channel *c)
|
||||||
@ -381,11 +393,16 @@ chn_rdfeed(struct pcm_channel *c)
|
|||||||
sndbuf_dump(bs, "bs", 0x02);
|
sndbuf_dump(bs, "bs", 0x02);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
#if 0
|
||||||
amt = sndbuf_getready(b);
|
amt = sndbuf_getready(b);
|
||||||
if (sndbuf_getfree(bs) < amt) {
|
if (sndbuf_getfree(bs) < amt) {
|
||||||
c->xruns++;
|
c->xruns++;
|
||||||
amt = sndbuf_getfree(bs);
|
amt = sndbuf_getfree(bs);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
amt = sndbuf_getfree(bs);
|
||||||
|
if (amt < sndbuf_getready(b))
|
||||||
|
c->xruns++;
|
||||||
ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
|
ret = (amt > 0)? sndbuf_feed(b, bs, c, c->feeder, amt) : 0;
|
||||||
|
|
||||||
amt = sndbuf_getready(b);
|
amt = sndbuf_getready(b);
|
||||||
@ -535,10 +552,12 @@ chn_start(struct pcm_channel *c, int force)
|
|||||||
* fed at the first irq.
|
* fed at the first irq.
|
||||||
*/
|
*/
|
||||||
if (c->direction == PCMDIR_PLAY) {
|
if (c->direction == PCMDIR_PLAY) {
|
||||||
|
/*
|
||||||
|
* Reduce pops during playback startup.
|
||||||
|
*/
|
||||||
|
sndbuf_fillsilence(b);
|
||||||
if (SLIST_EMPTY(&c->children))
|
if (SLIST_EMPTY(&c->children))
|
||||||
chn_wrfeed(c);
|
chn_wrfeed(c);
|
||||||
else
|
|
||||||
sndbuf_fillsilence(b);
|
|
||||||
}
|
}
|
||||||
sndbuf_setrun(b, 1);
|
sndbuf_setrun(b, 1);
|
||||||
c->xruns = 0;
|
c->xruns = 0;
|
||||||
@ -735,18 +754,24 @@ chn_reset(struct pcm_channel *c, u_int32_t fmt)
|
|||||||
|
|
||||||
r = CHANNEL_RESET(c->methods, c->devinfo);
|
r = CHANNEL_RESET(c->methods, c->devinfo);
|
||||||
if (fmt != 0) {
|
if (fmt != 0) {
|
||||||
|
#if 0
|
||||||
hwspd = DSP_DEFAULT_SPEED;
|
hwspd = DSP_DEFAULT_SPEED;
|
||||||
/* only do this on a record channel until feederbuilder works */
|
/* only do this on a record channel until feederbuilder works */
|
||||||
if (c->direction == PCMDIR_REC)
|
if (c->direction == PCMDIR_REC)
|
||||||
RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
|
RANGE(hwspd, chn_getcaps(c)->minspeed, chn_getcaps(c)->maxspeed);
|
||||||
c->speed = hwspd;
|
c->speed = hwspd;
|
||||||
|
#endif
|
||||||
|
hwspd = chn_getcaps(c)->minspeed;
|
||||||
|
c->speed = hwspd;
|
||||||
|
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = chn_setformat(c, fmt);
|
r = chn_setformat(c, fmt);
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = chn_setspeed(c, hwspd);
|
r = chn_setspeed(c, hwspd);
|
||||||
|
#if 0
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = chn_setvolume(c, 100, 100);
|
r = chn_setvolume(c, 100, 100);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = chn_setblocksize(c, 0, 0);
|
r = chn_setblocksize(c, 0, 0);
|
||||||
@ -886,7 +911,15 @@ chn_setvolume(struct pcm_channel *c, int left, int right)
|
|||||||
{
|
{
|
||||||
CHN_LOCKASSERT(c);
|
CHN_LOCKASSERT(c);
|
||||||
/* should add a feeder for volume changing if channel returns -1 */
|
/* should add a feeder for volume changing if channel returns -1 */
|
||||||
c->volume = (left << 8) | right;
|
if (left > 100)
|
||||||
|
left = 100;
|
||||||
|
if (left < 0)
|
||||||
|
left = 0;
|
||||||
|
if (right > 100)
|
||||||
|
right = 100;
|
||||||
|
if (right < 0)
|
||||||
|
right = 0;
|
||||||
|
c->volume = left | (right << 8);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -918,7 +951,10 @@ chn_tryspeed(struct pcm_channel *c, int speed)
|
|||||||
delta = -delta;
|
delta = -delta;
|
||||||
|
|
||||||
c->feederflags &= ~(1 << FEEDER_RATE);
|
c->feederflags &= ~(1 << FEEDER_RATE);
|
||||||
if (delta > 500)
|
/*
|
||||||
|
* Used to be 500. It was too big!
|
||||||
|
*/
|
||||||
|
if (delta > 25)
|
||||||
c->feederflags |= 1 << FEEDER_RATE;
|
c->feederflags |= 1 << FEEDER_RATE;
|
||||||
else
|
else
|
||||||
sndbuf_setspd(bs, sndbuf_getspd(b));
|
sndbuf_setspd(bs, sndbuf_getspd(b));
|
||||||
@ -951,6 +987,11 @@ chn_tryspeed(struct pcm_channel *c, int speed)
|
|||||||
r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
|
r = FEEDER_SET(f, FEEDRATE_DST, sndbuf_getspd(x));
|
||||||
DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
|
DEB(printf("feeder_set(FEEDRATE_DST, %d) = %d\n", sndbuf_getspd(x), r));
|
||||||
out:
|
out:
|
||||||
|
if (!r)
|
||||||
|
r = CHANNEL_SETFORMAT(c->methods, c->devinfo,
|
||||||
|
sndbuf_getfmt(b));
|
||||||
|
if (!r)
|
||||||
|
sndbuf_setfmt(bs, c->format);
|
||||||
DEB(printf("setspeed done, r = %d\n", r));
|
DEB(printf("setspeed done, r = %d\n", r));
|
||||||
return r;
|
return r;
|
||||||
} else
|
} else
|
||||||
@ -1008,12 +1049,50 @@ chn_setformat(struct pcm_channel *c, u_int32_t fmt)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* given a bufsz value, round it to a power of 2 in the min-max range
|
||||||
|
* XXX only works if min and max are powers of 2
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
round_bufsz(int bufsz, int min, int max)
|
||||||
|
{
|
||||||
|
int tmp = min * 2;
|
||||||
|
|
||||||
|
KASSERT((min & (min-1)) == 0, ("min %d must be power of 2\n", min));
|
||||||
|
KASSERT((max & (max-1)) == 0, ("max %d must be power of 2\n", max));
|
||||||
|
while (tmp <= bufsz)
|
||||||
|
tmp <<= 1;
|
||||||
|
tmp >>= 1;
|
||||||
|
if (tmp > max)
|
||||||
|
tmp = max;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set the channel's blocksize both for soft and hard buffers.
|
||||||
|
*
|
||||||
|
* blksz should be a power of 2 between 2**4 and 2**16 -- it is useful
|
||||||
|
* that it has the same value for both bufsoft and bufhard.
|
||||||
|
* blksz == -1 computes values according to a target irq rate.
|
||||||
|
* blksz == 0 reuses previous values if available, otherwise
|
||||||
|
* behaves as for -1
|
||||||
|
*
|
||||||
|
* blkcnt is set by the user, between 2 and (2**17)/blksz for bufsoft,
|
||||||
|
* but should be a power of 2 for bufhard to simplify life to low
|
||||||
|
* level drivers.
|
||||||
|
* Note, for the rec channel a large blkcnt is ok,
|
||||||
|
* but for the play channel we want blksz as small as possible to keep
|
||||||
|
* the delay small, because routines in the write path always try to
|
||||||
|
* keep bufhard full.
|
||||||
|
*
|
||||||
|
* Unless we have good reason to, use the values suggested by the caller.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
|
chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
|
||||||
{
|
{
|
||||||
struct snd_dbuf *b = c->bufhard;
|
struct snd_dbuf *b = c->bufhard;
|
||||||
struct snd_dbuf *bs = c->bufsoft;
|
struct snd_dbuf *bs = c->bufsoft;
|
||||||
int irqhz, tmp, ret, maxsize, reqblksz, tmpblksz;
|
int irqhz, ret, maxsz, maxsize, reqblksz;
|
||||||
|
|
||||||
CHN_LOCKASSERT(c);
|
CHN_LOCKASSERT(c);
|
||||||
if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) {
|
if (!CANCHANGE(c) || (c->flags & CHN_F_MAPPED)) {
|
||||||
@ -1027,27 +1106,30 @@ chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
|
|||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz));
|
DEB(printf("%s(%d, %d)\n", __func__, blkcnt, blksz));
|
||||||
if (blksz == 0 || blksz == -1) {
|
if (blksz == 0 || blksz == -1) { /* let the driver choose values */
|
||||||
if (blksz == -1)
|
if (blksz == -1) /* delete previous values */
|
||||||
c->flags &= ~CHN_F_HAS_SIZE;
|
c->flags &= ~CHN_F_HAS_SIZE;
|
||||||
if (!(c->flags & CHN_F_HAS_SIZE)) {
|
if (!(c->flags & CHN_F_HAS_SIZE)) { /* no previous value */
|
||||||
blksz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / chn_targetirqrate;
|
/*
|
||||||
tmp = 32;
|
* compute a base blksz according to the target irq
|
||||||
while (tmp <= blksz)
|
* rate, then round to a suitable power of 2
|
||||||
tmp <<= 1;
|
* in the range 16.. 2^17/2.
|
||||||
tmp >>= 1;
|
* Finally compute a suitable blkcnt.
|
||||||
blksz = tmp;
|
*/
|
||||||
|
blksz = round_bufsz( (sndbuf_getbps(bs) *
|
||||||
|
sndbuf_getspd(bs)) / chn_targetirqrate,
|
||||||
|
16, CHN_2NDBUFMAXSIZE / 2);
|
||||||
blkcnt = CHN_2NDBUFMAXSIZE / blksz;
|
blkcnt = CHN_2NDBUFMAXSIZE / blksz;
|
||||||
|
} else { /* use previously defined value */
|
||||||
RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2);
|
|
||||||
RANGE(blkcnt, 2, CHN_2NDBUFMAXSIZE / blksz);
|
|
||||||
DEB(printf("%s: defaulting to (%d, %d)\n", __func__, blkcnt, blksz));
|
|
||||||
} else {
|
|
||||||
blkcnt = sndbuf_getblkcnt(bs);
|
blkcnt = sndbuf_getblkcnt(bs);
|
||||||
blksz = sndbuf_getblksz(bs);
|
blksz = sndbuf_getblksz(bs);
|
||||||
DEB(printf("%s: updating (%d, %d)\n", __func__, blkcnt, blksz));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* use supplied values if reasonable. Note that here we
|
||||||
|
* might have blksz which is not a power of 2 if the
|
||||||
|
* ioctl() to compute it allows such values.
|
||||||
|
*/
|
||||||
ret = EINVAL;
|
ret = EINVAL;
|
||||||
if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE))
|
if ((blksz < 16) || (blkcnt < 2) || (blkcnt * blksz > CHN_2NDBUFMAXSIZE))
|
||||||
goto out;
|
goto out;
|
||||||
@ -1056,27 +1138,29 @@ chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
reqblksz = blksz;
|
reqblksz = blksz;
|
||||||
|
if (reqblksz < sndbuf_getbps(bs))
|
||||||
|
reqblksz = sndbuf_getbps(bs);
|
||||||
|
if (reqblksz % sndbuf_getbps(bs))
|
||||||
|
reqblksz -= reqblksz % sndbuf_getbps(bs);
|
||||||
|
|
||||||
/* adjust for different hw format/speed */
|
/* adjust for different hw format/speed */
|
||||||
|
/*
|
||||||
|
* Now compute the approx irq rate for the given (soft) blksz,
|
||||||
|
* reduce to the acceptable range and compute a corresponding blksz
|
||||||
|
* for the hard buffer. Then set the channel's blocksize and
|
||||||
|
* corresponding hardbuf value. The number of blocks used should
|
||||||
|
* be set by the device-specific routine. In fact, even the
|
||||||
|
* call to sndbuf_setblksz() should not be here! XXX
|
||||||
|
*/
|
||||||
|
|
||||||
irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz;
|
irqhz = (sndbuf_getbps(bs) * sndbuf_getspd(bs)) / blksz;
|
||||||
DEB(printf("%s: soft bps %d, spd %d, irqhz == %d\n", __func__, sndbuf_getbps(bs), sndbuf_getspd(bs), irqhz));
|
|
||||||
RANGE(irqhz, 16, 512);
|
RANGE(irqhz, 16, 512);
|
||||||
|
|
||||||
tmpblksz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz;
|
maxsz = sndbuf_getmaxsize(b);
|
||||||
|
if (maxsz == 0) /* virtual channels don't appear to allocate bufhard */
|
||||||
/* round down to 2^x */
|
maxsz = CHN_2NDBUFMAXSIZE;
|
||||||
blksz = 32;
|
blksz = round_bufsz( (sndbuf_getbps(b) * sndbuf_getspd(b)) / irqhz,
|
||||||
while (blksz <= tmpblksz)
|
16, maxsz / 2);
|
||||||
blksz <<= 1;
|
|
||||||
blksz >>= 1;
|
|
||||||
|
|
||||||
/* round down to fit hw buffer size */
|
|
||||||
if (sndbuf_getmaxsize(b) > 0)
|
|
||||||
RANGE(blksz, 16, sndbuf_getmaxsize(b) / 2);
|
|
||||||
else
|
|
||||||
/* virtual channels don't appear to allocate bufhard */
|
|
||||||
RANGE(blksz, 16, CHN_2NDBUFMAXSIZE / 2);
|
|
||||||
DEB(printf("%s: hard blksz requested %d (maxsize %d), ", __func__, blksz, sndbuf_getmaxsize(b)));
|
|
||||||
|
|
||||||
/* Increase the size of bufsoft if before increasing bufhard. */
|
/* Increase the size of bufsoft if before increasing bufhard. */
|
||||||
maxsize = sndbuf_getsize(b);
|
maxsize = sndbuf_getsize(b);
|
||||||
@ -1107,9 +1191,6 @@ chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
|
|||||||
goto out1;
|
goto out1;
|
||||||
}
|
}
|
||||||
|
|
||||||
irqhz = (sndbuf_getbps(b) * sndbuf_getspd(b)) / sndbuf_getblksz(b);
|
|
||||||
DEB(printf("got %d, irqhz == %d\n", sndbuf_getblksz(b), irqhz));
|
|
||||||
|
|
||||||
chn_resetbuf(c);
|
chn_resetbuf(c);
|
||||||
out1:
|
out1:
|
||||||
KASSERT(sndbuf_getsize(bs) == 0 ||
|
KASSERT(sndbuf_getsize(bs) == 0 ||
|
||||||
@ -1119,6 +1200,24 @@ chn_setblocksize(struct pcm_channel *c, int blkcnt, int blksz)
|
|||||||
blksz, maxsize, blkcnt));
|
blksz, maxsize, blkcnt));
|
||||||
out:
|
out:
|
||||||
c->flags &= ~CHN_F_SETBLOCKSIZE;
|
c->flags &= ~CHN_F_SETBLOCKSIZE;
|
||||||
|
#if 0
|
||||||
|
if (1) {
|
||||||
|
static uint32_t kk = 0;
|
||||||
|
printf("%u: b %d/%d/%d : (%d)%d/0x%0x | bs %d/%d/%d : (%d)%d/0x%0x\n", ++kk,
|
||||||
|
sndbuf_getsize(b), sndbuf_getblksz(b), sndbuf_getblkcnt(b),
|
||||||
|
sndbuf_getbps(b),
|
||||||
|
sndbuf_getspd(b), sndbuf_getfmt(b),
|
||||||
|
sndbuf_getsize(bs), sndbuf_getblksz(bs), sndbuf_getblkcnt(bs),
|
||||||
|
sndbuf_getbps(bs),
|
||||||
|
sndbuf_getspd(bs), sndbuf_getfmt(bs));
|
||||||
|
if (sndbuf_getsize(b) % sndbuf_getbps(b) ||
|
||||||
|
sndbuf_getblksz(b) % sndbuf_getbps(b) ||
|
||||||
|
sndbuf_getsize(bs) % sndbuf_getbps(bs) ||
|
||||||
|
sndbuf_getblksz(b) % sndbuf_getbps(b)) {
|
||||||
|
printf("%u: bps/blksz alignment screwed!\n", kk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1176,7 +1275,9 @@ chn_getformats(struct pcm_channel *c)
|
|||||||
|
|
||||||
/* report software-supported formats */
|
/* report software-supported formats */
|
||||||
if (report_soft_formats)
|
if (report_soft_formats)
|
||||||
fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U16_LE|AFMT_U16_BE|
|
fmts |= AFMT_MU_LAW|AFMT_A_LAW|AFMT_U32_LE|AFMT_U32_BE|
|
||||||
|
AFMT_S32_LE|AFMT_S32_BE|AFMT_U24_LE|AFMT_U24_BE|
|
||||||
|
AFMT_S24_LE|AFMT_S24_BE|AFMT_U16_LE|AFMT_U16_BE|
|
||||||
AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
|
AFMT_S16_LE|AFMT_S16_BE|AFMT_U8|AFMT_S8;
|
||||||
|
|
||||||
return fmts;
|
return fmts;
|
||||||
@ -1187,7 +1288,7 @@ chn_buildfeeder(struct pcm_channel *c)
|
|||||||
{
|
{
|
||||||
struct feeder_class *fc;
|
struct feeder_class *fc;
|
||||||
struct pcm_feederdesc desc;
|
struct pcm_feederdesc desc;
|
||||||
u_int32_t tmp[2], type, flags, hwfmt;
|
u_int32_t tmp[2], type, flags, hwfmt, *fmtlist;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
CHN_LOCKASSERT(c);
|
CHN_LOCKASSERT(c);
|
||||||
@ -1208,8 +1309,13 @@ chn_buildfeeder(struct pcm_channel *c)
|
|||||||
}
|
}
|
||||||
c->feeder->desc->out = c->format;
|
c->feeder->desc->out = c->format;
|
||||||
} else {
|
} else {
|
||||||
|
if (c->flags & CHN_F_HAS_VCHAN) {
|
||||||
desc.type = FEEDER_MIXER;
|
desc.type = FEEDER_MIXER;
|
||||||
desc.in = 0;
|
desc.in = 0;
|
||||||
|
} else {
|
||||||
|
DEB(printf("can't decide which feeder type to use!\n"));
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
desc.out = c->format;
|
desc.out = c->format;
|
||||||
desc.flags = 0;
|
desc.flags = 0;
|
||||||
fc = feeder_getclass(&desc);
|
fc = feeder_getclass(&desc);
|
||||||
@ -1226,7 +1332,14 @@ chn_buildfeeder(struct pcm_channel *c)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
c->feederflags &= ~(1 << FEEDER_VOLUME);
|
||||||
|
if (c->direction == PCMDIR_PLAY &&
|
||||||
|
!(c->flags & CHN_F_VIRTUAL) &&
|
||||||
|
c->parentsnddev && (c->parentsnddev->flags & SD_F_SOFTVOL) &&
|
||||||
|
c->parentsnddev->mixer_dev)
|
||||||
|
c->feederflags |= 1 << FEEDER_VOLUME;
|
||||||
flags = c->feederflags;
|
flags = c->feederflags;
|
||||||
|
fmtlist = chn_getcaps(c)->fmtlist;
|
||||||
|
|
||||||
DEB(printf("feederflags %x\n", flags));
|
DEB(printf("feederflags %x\n", flags));
|
||||||
|
|
||||||
@ -1245,7 +1358,9 @@ chn_buildfeeder(struct pcm_channel *c)
|
|||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->feeder->desc->out != fc->desc->in) {
|
if ((type == FEEDER_RATE &&
|
||||||
|
!fmtvalid(fc->desc->in, fmtlist))
|
||||||
|
|| c->feeder->desc->out != fc->desc->in) {
|
||||||
DEB(printf("build fmtchain from 0x%x to 0x%x: ", c->feeder->desc->out, fc->desc->in));
|
DEB(printf("build fmtchain from 0x%x to 0x%x: ", c->feeder->desc->out, fc->desc->in));
|
||||||
tmp[0] = fc->desc->in;
|
tmp[0] = fc->desc->in;
|
||||||
tmp[1] = 0;
|
tmp[1] = 0;
|
||||||
@ -1267,31 +1382,42 @@ chn_buildfeeder(struct pcm_channel *c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmtvalid(c->feeder->desc->out, chn_getcaps(c)->fmtlist)) {
|
if (fmtvalid(c->feeder->desc->out, fmtlist)
|
||||||
|
&& !(c->direction == PCMDIR_REC &&
|
||||||
|
c->format != c->feeder->desc->out))
|
||||||
hwfmt = c->feeder->desc->out;
|
hwfmt = c->feeder->desc->out;
|
||||||
} else {
|
else {
|
||||||
if (c->direction == PCMDIR_REC) {
|
if (c->direction == PCMDIR_REC) {
|
||||||
tmp[0] = c->format;
|
tmp[0] = c->format;
|
||||||
tmp[1] = 0;
|
tmp[1] = 0;
|
||||||
hwfmt = chn_fmtchain(c, tmp);
|
hwfmt = chn_fmtchain(c, tmp);
|
||||||
} else {
|
} else
|
||||||
#if 0
|
hwfmt = chn_fmtchain(c, fmtlist);
|
||||||
u_int32_t *x = chn_getcaps(c)->fmtlist;
|
|
||||||
printf("acceptable formats for %s:\n", c->name);
|
|
||||||
while (*x) {
|
|
||||||
printf("[0x%8x] ", *x);
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
hwfmt = chn_fmtchain(c, chn_getcaps(c)->fmtlist);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hwfmt == 0)
|
if (hwfmt == 0 || !fmtvalid(hwfmt, fmtlist)) {
|
||||||
|
DEB(printf("Invalid hardware format: 0x%x\n", hwfmt));
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
sndbuf_setfmt(c->bufhard, hwfmt);
|
sndbuf_setfmt(c->bufhard, hwfmt);
|
||||||
|
|
||||||
|
if ((flags & (1 << FEEDER_VOLUME))) {
|
||||||
|
int vol = 100 | (100 << 8);
|
||||||
|
|
||||||
|
CHN_UNLOCK(c);
|
||||||
|
/*
|
||||||
|
* XXX This is ugly! The way mixer subs being so secretive
|
||||||
|
* about its own internals force us to use this silly
|
||||||
|
* monkey trick.
|
||||||
|
*/
|
||||||
|
if (mixer_ioctl(c->parentsnddev->mixer_dev,
|
||||||
|
MIXER_READ(SOUND_MIXER_PCM), (caddr_t)&vol, -1, NULL) != 0)
|
||||||
|
device_printf(c->dev, "Soft Volume: Failed to read default value\n");
|
||||||
|
CHN_LOCK(c);
|
||||||
|
chn_setvolume(c, vol & 0x7f, (vol >> 8) & 0x7f);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,10 +137,13 @@ int fmtvalid(u_int32_t fmt, u_int32_t *fmtlist);
|
|||||||
#define CHN_F_DEAD 0x00020000
|
#define CHN_F_DEAD 0x00020000
|
||||||
#define CHN_F_BADSETTING 0x00040000
|
#define CHN_F_BADSETTING 0x00040000
|
||||||
#define CHN_F_SETBLOCKSIZE 0x00080000
|
#define CHN_F_SETBLOCKSIZE 0x00080000
|
||||||
|
#define CHN_F_HAS_VCHAN 0x00100000
|
||||||
|
|
||||||
#define CHN_F_VIRTUAL 0x10000000 /* not backed by hardware */
|
#define CHN_F_VIRTUAL 0x10000000 /* not backed by hardware */
|
||||||
|
|
||||||
#define CHN_F_RESET (CHN_F_BUSY | CHN_F_DEAD | CHN_F_VIRTUAL)
|
#define CHN_F_RESET (CHN_F_BUSY | CHN_F_DEAD | \
|
||||||
|
CHN_F_HAS_VCHAN | CHN_F_VIRTUAL)
|
||||||
|
|
||||||
|
|
||||||
#define CHN_N_RATE 0x00000001
|
#define CHN_N_RATE 0x00000001
|
||||||
#define CHN_N_FORMAT 0x00000002
|
#define CHN_N_FORMAT 0x00000002
|
||||||
|
@ -168,13 +168,11 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct pcm_channel *rdch, *wrch;
|
struct pcm_channel *rdch, *wrch;
|
||||||
struct snddev_info *d;
|
struct snddev_info *d;
|
||||||
intrmask_t s;
|
|
||||||
u_int32_t fmt;
|
u_int32_t fmt;
|
||||||
int devtype;
|
int devtype;
|
||||||
int rdref;
|
int rdref;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
d = dsp_get_info(i_dev);
|
d = dsp_get_info(i_dev);
|
||||||
devtype = PCMDEV(i_dev);
|
devtype = PCMDEV(i_dev);
|
||||||
|
|
||||||
@ -199,7 +197,6 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
case SND_DEV_DSPREC:
|
case SND_DEV_DSPREC:
|
||||||
fmt = AFMT_U8;
|
fmt = AFMT_U8;
|
||||||
if (mode & FWRITE) {
|
if (mode & FWRITE) {
|
||||||
splx(s);
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -219,7 +216,6 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
if ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && (rdch || wrch)) {
|
if ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && (rdch || wrch)) {
|
||||||
/* we're a simplex device and already open, no go */
|
/* we're a simplex device and already open, no go */
|
||||||
pcm_unlock(d);
|
pcm_unlock(d);
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +225,6 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
* the opener wants; we can't handle this.
|
* the opener wants; we can't handle this.
|
||||||
*/
|
*/
|
||||||
pcm_unlock(d);
|
pcm_unlock(d);
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,25 +236,23 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
*/
|
*/
|
||||||
if (flags & FREAD) {
|
if (flags & FREAD) {
|
||||||
/* open for read */
|
/* open for read */
|
||||||
|
pcm_unlock(d);
|
||||||
if (devtype == SND_DEV_DSPREC)
|
if (devtype == SND_DEV_DSPREC)
|
||||||
rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, PCMCHAN(i_dev));
|
rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, PCMCHAN(i_dev));
|
||||||
else
|
else
|
||||||
rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, -1);
|
rdch = pcm_chnalloc(d, PCMDIR_REC, td->td_proc->p_pid, -1);
|
||||||
if (!rdch) {
|
if (!rdch) {
|
||||||
/* no channel available, exit */
|
/* no channel available, exit */
|
||||||
pcm_unlock(d);
|
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
/* got a channel, already locked for us */
|
/* got a channel, already locked for us */
|
||||||
if (chn_reset(rdch, fmt)) {
|
if (chn_reset(rdch, fmt)) {
|
||||||
pcm_chnrelease(rdch);
|
pcm_chnrelease(rdch);
|
||||||
i_dev->si_drv1 = NULL;
|
i_dev->si_drv1 = NULL;
|
||||||
pcm_unlock(d);
|
|
||||||
splx(s);
|
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcm_lock(d);
|
||||||
if (flags & O_NONBLOCK)
|
if (flags & O_NONBLOCK)
|
||||||
rdch->flags |= CHN_F_NBIO;
|
rdch->flags |= CHN_F_NBIO;
|
||||||
pcm_chnref(rdch, 1);
|
pcm_chnref(rdch, 1);
|
||||||
@ -272,6 +265,7 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
|
|
||||||
if (flags & FWRITE) {
|
if (flags & FWRITE) {
|
||||||
/* open for write */
|
/* open for write */
|
||||||
|
pcm_unlock(d);
|
||||||
wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
|
wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
|
||||||
error = 0;
|
error = 0;
|
||||||
|
|
||||||
@ -280,6 +274,7 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
else if (chn_reset(wrch, fmt))
|
else if (chn_reset(wrch, fmt))
|
||||||
error = ENODEV;
|
error = ENODEV;
|
||||||
|
|
||||||
|
pcm_lock(d);
|
||||||
if (error != 0) {
|
if (error != 0) {
|
||||||
if (wrch) {
|
if (wrch) {
|
||||||
/*
|
/*
|
||||||
@ -299,7 +294,6 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pcm_unlock(d);
|
pcm_unlock(d);
|
||||||
splx(s);
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,7 +307,6 @@ dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
i_dev->si_drv2 = wrch;
|
i_dev->si_drv2 = wrch;
|
||||||
|
|
||||||
pcm_unlock(d);
|
pcm_unlock(d);
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,12 +315,9 @@ dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct pcm_channel *rdch, *wrch;
|
struct pcm_channel *rdch, *wrch;
|
||||||
struct snddev_info *d;
|
struct snddev_info *d;
|
||||||
intrmask_t s;
|
|
||||||
int refs;
|
int refs;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
d = dsp_get_info(i_dev);
|
d = dsp_get_info(i_dev);
|
||||||
pcm_lock(d);
|
|
||||||
rdch = i_dev->si_drv1;
|
rdch = i_dev->si_drv1;
|
||||||
wrch = i_dev->si_drv2;
|
wrch = i_dev->si_drv2;
|
||||||
|
|
||||||
@ -349,6 +339,8 @@ dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
*/
|
*/
|
||||||
if ((rdch || wrch) && refs == 0) {
|
if ((rdch || wrch) && refs == 0) {
|
||||||
|
|
||||||
|
pcm_lock(d);
|
||||||
|
|
||||||
if (pcm_getfakechan(d))
|
if (pcm_getfakechan(d))
|
||||||
pcm_getfakechan(d)->flags = 0;
|
pcm_getfakechan(d)->flags = 0;
|
||||||
|
|
||||||
@ -380,9 +372,7 @@ dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
chn_reset(wrch, 0);
|
chn_reset(wrch, 0);
|
||||||
pcm_chnrelease(wrch);
|
pcm_chnrelease(wrch);
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
pcm_unlock(d);
|
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,10 +380,8 @@ static int
|
|||||||
dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
|
dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
|
||||||
{
|
{
|
||||||
struct pcm_channel *rdch, *wrch;
|
struct pcm_channel *rdch, *wrch;
|
||||||
intrmask_t s;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD);
|
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD);
|
||||||
|
|
||||||
KASSERT(rdch, ("dsp_read: nonexistant channel"));
|
KASSERT(rdch, ("dsp_read: nonexistant channel"));
|
||||||
@ -401,7 +389,6 @@ dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
|
|||||||
|
|
||||||
if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
|
if (rdch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
|
||||||
splx(s);
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!(rdch->flags & CHN_F_RUNNING))
|
if (!(rdch->flags & CHN_F_RUNNING))
|
||||||
@ -409,7 +396,6 @@ dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
|
|||||||
ret = chn_read(rdch, buf);
|
ret = chn_read(rdch, buf);
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD);
|
||||||
|
|
||||||
splx(s);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,10 +403,8 @@ static int
|
|||||||
dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
|
dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
|
||||||
{
|
{
|
||||||
struct pcm_channel *rdch, *wrch;
|
struct pcm_channel *rdch, *wrch;
|
||||||
intrmask_t s;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR);
|
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_WR);
|
||||||
|
|
||||||
KASSERT(wrch, ("dsp_write: nonexistant channel"));
|
KASSERT(wrch, ("dsp_write: nonexistant channel"));
|
||||||
@ -428,7 +412,6 @@ dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
|
|||||||
|
|
||||||
if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
|
if (wrch->flags & (CHN_F_MAPPED | CHN_F_DEAD)) {
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
|
||||||
splx(s);
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (!(wrch->flags & CHN_F_RUNNING))
|
if (!(wrch->flags & CHN_F_RUNNING))
|
||||||
@ -436,7 +419,6 @@ dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
|
|||||||
ret = chn_write(wrch, buf);
|
ret = chn_write(wrch, buf);
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_WR);
|
||||||
|
|
||||||
splx(s);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +427,6 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
{
|
{
|
||||||
struct pcm_channel *chn, *rdch, *wrch;
|
struct pcm_channel *chn, *rdch, *wrch;
|
||||||
struct snddev_info *d;
|
struct snddev_info *d;
|
||||||
intrmask_t s;
|
|
||||||
int kill;
|
int kill;
|
||||||
int ret = 0, *arg_i = (int *)arg, tmp;
|
int ret = 0, *arg_i = (int *)arg, tmp;
|
||||||
|
|
||||||
@ -458,7 +439,6 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
if (IOCGROUP(cmd) == 'M')
|
if (IOCGROUP(cmd) == 'M')
|
||||||
return mixer_ioctl(d->mixer_dev, cmd, arg, mode, td);
|
return mixer_ioctl(d->mixer_dev, cmd, arg, mode, td);
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
getchns(i_dev, &rdch, &wrch, 0);
|
getchns(i_dev, &rdch, &wrch, 0);
|
||||||
|
|
||||||
kill = 0;
|
kill = 0;
|
||||||
@ -468,7 +448,6 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
kill |= 2;
|
kill |= 2;
|
||||||
if (kill == 3) {
|
if (kill == 3) {
|
||||||
relchns(i_dev, rdch, wrch, 0);
|
relchns(i_dev, rdch, wrch, 0);
|
||||||
splx(s);
|
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
if (kill & 1)
|
if (kill & 1)
|
||||||
@ -533,9 +512,15 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
{
|
{
|
||||||
snd_chan_param *p = (snd_chan_param *)arg;
|
snd_chan_param *p = (snd_chan_param *)arg;
|
||||||
|
|
||||||
|
if (cmd == AIOSFMT &&
|
||||||
|
((p->play_format != 0 && p->play_rate == 0) ||
|
||||||
|
(p->rec_format != 0 && p->rec_rate == 0))) {
|
||||||
|
ret = EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (wrch) {
|
if (wrch) {
|
||||||
CHN_LOCK(wrch);
|
CHN_LOCK(wrch);
|
||||||
if (cmd == AIOSFMT) {
|
if (cmd == AIOSFMT && p->play_format != 0) {
|
||||||
chn_setformat(wrch, p->play_format);
|
chn_setformat(wrch, p->play_format);
|
||||||
chn_setspeed(wrch, p->play_rate);
|
chn_setspeed(wrch, p->play_rate);
|
||||||
}
|
}
|
||||||
@ -548,7 +533,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
}
|
}
|
||||||
if (rdch) {
|
if (rdch) {
|
||||||
CHN_LOCK(rdch);
|
CHN_LOCK(rdch);
|
||||||
if (cmd == AIOSFMT) {
|
if (cmd == AIOSFMT && p->rec_format != 0) {
|
||||||
chn_setformat(rdch, p->rec_format);
|
chn_setformat(rdch, p->rec_format);
|
||||||
chn_setspeed(rdch, p->rec_rate);
|
chn_setspeed(rdch, p->rec_rate);
|
||||||
}
|
}
|
||||||
@ -826,6 +811,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
u_int32_t fragln = (*arg_i) & 0x0000ffff;
|
u_int32_t fragln = (*arg_i) & 0x0000ffff;
|
||||||
u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
|
u_int32_t maxfrags = ((*arg_i) & 0xffff0000) >> 16;
|
||||||
u_int32_t fragsz;
|
u_int32_t fragsz;
|
||||||
|
u_int32_t r_maxfrags, r_fragsz;
|
||||||
|
|
||||||
RANGE(fragln, 4, 16);
|
RANGE(fragln, 4, 16);
|
||||||
fragsz = 1 << fragln;
|
fragsz = 1 << fragln;
|
||||||
@ -841,9 +827,12 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
if (rdch) {
|
if (rdch) {
|
||||||
CHN_LOCK(rdch);
|
CHN_LOCK(rdch);
|
||||||
ret = chn_setblocksize(rdch, maxfrags, fragsz);
|
ret = chn_setblocksize(rdch, maxfrags, fragsz);
|
||||||
maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
|
r_maxfrags = sndbuf_getblkcnt(rdch->bufsoft);
|
||||||
fragsz = sndbuf_getblksz(rdch->bufsoft);
|
r_fragsz = sndbuf_getblksz(rdch->bufsoft);
|
||||||
CHN_UNLOCK(rdch);
|
CHN_UNLOCK(rdch);
|
||||||
|
} else {
|
||||||
|
r_maxfrags = maxfrags;
|
||||||
|
r_fragsz = fragsz;
|
||||||
}
|
}
|
||||||
if (wrch && ret == 0) {
|
if (wrch && ret == 0) {
|
||||||
CHN_LOCK(wrch);
|
CHN_LOCK(wrch);
|
||||||
@ -851,6 +840,9 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
|
maxfrags = sndbuf_getblkcnt(wrch->bufsoft);
|
||||||
fragsz = sndbuf_getblksz(wrch->bufsoft);
|
fragsz = sndbuf_getblksz(wrch->bufsoft);
|
||||||
CHN_UNLOCK(wrch);
|
CHN_UNLOCK(wrch);
|
||||||
|
} else { /* use whatever came from the read channel */
|
||||||
|
maxfrags = r_maxfrags;
|
||||||
|
fragsz = r_fragsz;
|
||||||
}
|
}
|
||||||
|
|
||||||
fragln = 0;
|
fragln = 0;
|
||||||
@ -887,7 +879,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
struct snd_dbuf *bs = wrch->bufsoft;
|
struct snd_dbuf *bs = wrch->bufsoft;
|
||||||
|
|
||||||
CHN_LOCK(wrch);
|
CHN_LOCK(wrch);
|
||||||
chn_wrupdate(wrch);
|
/* XXX abusive DMA update: chn_wrupdate(wrch); */
|
||||||
a->bytes = sndbuf_getfree(bs);
|
a->bytes = sndbuf_getfree(bs);
|
||||||
a->fragments = a->bytes / sndbuf_getblksz(bs);
|
a->fragments = a->bytes / sndbuf_getblksz(bs);
|
||||||
a->fragstotal = sndbuf_getblkcnt(bs);
|
a->fragstotal = sndbuf_getblkcnt(bs);
|
||||||
@ -904,7 +896,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
struct snd_dbuf *bs = rdch->bufsoft;
|
struct snd_dbuf *bs = rdch->bufsoft;
|
||||||
|
|
||||||
CHN_LOCK(rdch);
|
CHN_LOCK(rdch);
|
||||||
chn_rdupdate(rdch);
|
/* XXX abusive DMA update: chn_rdupdate(rdch); */
|
||||||
a->bytes = sndbuf_gettotal(bs);
|
a->bytes = sndbuf_gettotal(bs);
|
||||||
a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
|
a->blocks = sndbuf_getblocks(bs) - rdch->blocks;
|
||||||
a->ptr = sndbuf_getreadyptr(bs);
|
a->ptr = sndbuf_getreadyptr(bs);
|
||||||
@ -922,7 +914,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
struct snd_dbuf *bs = wrch->bufsoft;
|
struct snd_dbuf *bs = wrch->bufsoft;
|
||||||
|
|
||||||
CHN_LOCK(wrch);
|
CHN_LOCK(wrch);
|
||||||
chn_wrupdate(wrch);
|
/* XXX abusive DMA update: chn_wrupdate(wrch); */
|
||||||
a->bytes = sndbuf_gettotal(bs);
|
a->bytes = sndbuf_gettotal(bs);
|
||||||
a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
|
a->blocks = sndbuf_getblocks(bs) - wrch->blocks;
|
||||||
a->ptr = sndbuf_getreadyptr(bs);
|
a->ptr = sndbuf_getreadyptr(bs);
|
||||||
@ -942,7 +934,16 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
case SOUND_PCM_READ_BITS:
|
case SOUND_PCM_READ_BITS:
|
||||||
chn = wrch ? wrch : rdch;
|
chn = wrch ? wrch : rdch;
|
||||||
CHN_LOCK(chn);
|
CHN_LOCK(chn);
|
||||||
*arg_i = (chn->format & AFMT_16BIT) ? 16 : 8;
|
if (chn->format & AFMT_8BIT)
|
||||||
|
*arg_i = 8;
|
||||||
|
else if (chn->format & AFMT_16BIT)
|
||||||
|
*arg_i = 16;
|
||||||
|
else if (chn->format & AFMT_24BIT)
|
||||||
|
*arg_i = 24;
|
||||||
|
else if (chn->format & AFMT_32BIT)
|
||||||
|
*arg_i = 32;
|
||||||
|
else
|
||||||
|
ret = EINVAL;
|
||||||
CHN_UNLOCK(chn);
|
CHN_UNLOCK(chn);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -989,7 +990,7 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
struct snd_dbuf *bs = wrch->bufsoft;
|
struct snd_dbuf *bs = wrch->bufsoft;
|
||||||
|
|
||||||
CHN_LOCK(wrch);
|
CHN_LOCK(wrch);
|
||||||
chn_wrupdate(wrch);
|
/* XXX abusive DMA update: chn_wrupdate(wrch); */
|
||||||
*arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
|
*arg_i = sndbuf_getready(b) + sndbuf_getready(bs);
|
||||||
CHN_UNLOCK(wrch);
|
CHN_UNLOCK(wrch);
|
||||||
} else
|
} else
|
||||||
@ -1030,7 +1031,6 @@ dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
relchns(i_dev, rdch, wrch, 0);
|
relchns(i_dev, rdch, wrch, 0);
|
||||||
splx(s);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1038,10 +1038,8 @@ static int
|
|||||||
dsp_poll(struct cdev *i_dev, int events, struct thread *td)
|
dsp_poll(struct cdev *i_dev, int events, struct thread *td)
|
||||||
{
|
{
|
||||||
struct pcm_channel *wrch = NULL, *rdch = NULL;
|
struct pcm_channel *wrch = NULL, *rdch = NULL;
|
||||||
intrmask_t s;
|
|
||||||
int ret, e;
|
int ret, e;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
||||||
|
|
||||||
@ -1057,7 +1055,6 @@ dsp_poll(struct cdev *i_dev, int events, struct thread *td)
|
|||||||
}
|
}
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
||||||
|
|
||||||
splx(s);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1065,12 +1062,10 @@ static int
|
|||||||
dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
||||||
{
|
{
|
||||||
struct pcm_channel *wrch = NULL, *rdch = NULL, *c;
|
struct pcm_channel *wrch = NULL, *rdch = NULL, *c;
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
if (nprot & PROT_EXEC)
|
if (nprot & PROT_EXEC)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
||||||
#if 0
|
#if 0
|
||||||
/*
|
/*
|
||||||
@ -1083,7 +1078,6 @@ dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
|||||||
} else if (rdch && (nprot & PROT_READ)) {
|
} else if (rdch && (nprot & PROT_READ)) {
|
||||||
c = rdch;
|
c = rdch;
|
||||||
} else {
|
} else {
|
||||||
splx(s);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -1092,13 +1086,11 @@ dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
|||||||
|
|
||||||
if (c == NULL) {
|
if (c == NULL) {
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
||||||
splx(s);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset >= sndbuf_getsize(c->bufsoft)) {
|
if (offset >= sndbuf_getsize(c->bufsoft)) {
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
||||||
splx(s);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,7 +1100,6 @@ dsp_mmap(struct cdev *i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
|
|||||||
*paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset));
|
*paddr = vtophys(sndbuf_getbufofs(c->bufsoft, offset));
|
||||||
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
|
||||||
|
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1173,7 +1164,7 @@ dsp_clone(void *arg, struct ucred *cred, char *name, int namelen,
|
|||||||
panic("Unknown devtype %d", devtype);
|
panic("Unknown devtype %d", devtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
|
if ((pdev != NULL) && (pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
|
||||||
*dev = pdev;
|
*dev = pdev;
|
||||||
dev_ref(*dev);
|
dev_ref(*dev);
|
||||||
return;
|
return;
|
||||||
|
@ -29,6 +29,10 @@
|
|||||||
SND_DECLARE_FILE("$FreeBSD$");
|
SND_DECLARE_FILE("$FreeBSD$");
|
||||||
|
|
||||||
static u_int32_t fk_fmt[] = {
|
static u_int32_t fk_fmt[] = {
|
||||||
|
AFMT_MU_LAW,
|
||||||
|
AFMT_STEREO | AFMT_MU_LAW,
|
||||||
|
AFMT_A_LAW,
|
||||||
|
AFMT_STEREO | AFMT_A_LAW,
|
||||||
AFMT_U8,
|
AFMT_U8,
|
||||||
AFMT_STEREO | AFMT_U8,
|
AFMT_STEREO | AFMT_U8,
|
||||||
AFMT_S8,
|
AFMT_S8,
|
||||||
@ -41,6 +45,22 @@ static u_int32_t fk_fmt[] = {
|
|||||||
AFMT_STEREO | AFMT_S16_BE,
|
AFMT_STEREO | AFMT_S16_BE,
|
||||||
AFMT_U16_BE,
|
AFMT_U16_BE,
|
||||||
AFMT_STEREO | AFMT_U16_BE,
|
AFMT_STEREO | AFMT_U16_BE,
|
||||||
|
AFMT_S24_LE,
|
||||||
|
AFMT_STEREO | AFMT_S24_LE,
|
||||||
|
AFMT_U24_LE,
|
||||||
|
AFMT_STEREO | AFMT_U24_LE,
|
||||||
|
AFMT_S24_BE,
|
||||||
|
AFMT_STEREO | AFMT_S24_BE,
|
||||||
|
AFMT_U24_BE,
|
||||||
|
AFMT_STEREO | AFMT_U24_BE,
|
||||||
|
AFMT_S32_LE,
|
||||||
|
AFMT_STEREO | AFMT_S32_LE,
|
||||||
|
AFMT_U32_LE,
|
||||||
|
AFMT_STEREO | AFMT_U32_LE,
|
||||||
|
AFMT_S32_BE,
|
||||||
|
AFMT_STEREO | AFMT_S32_BE,
|
||||||
|
AFMT_U32_BE,
|
||||||
|
AFMT_STEREO | AFMT_U32_BE,
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
static struct pcmchan_caps fk_caps = {0, 1000000, fk_fmt, 0};
|
static struct pcmchan_caps fk_caps = {0, 1000000, fk_fmt, 0};
|
||||||
@ -120,6 +140,12 @@ fkchan_setup(device_t dev)
|
|||||||
c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK);
|
c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK);
|
||||||
c->methods = kobj_create(&fkchan_class, M_DEVBUF, M_WAITOK);
|
c->methods = kobj_create(&fkchan_class, M_DEVBUF, M_WAITOK);
|
||||||
c->parentsnddev = d;
|
c->parentsnddev = d;
|
||||||
|
/*
|
||||||
|
* Fake channel is such a blessing in disguise. Using this,
|
||||||
|
* we can keep track prefered virtual channel speed without
|
||||||
|
* querying kernel hint repetitively (see vchan_create / vchan.c).
|
||||||
|
*/
|
||||||
|
c->speed = 0;
|
||||||
snprintf(c->name, CHN_NAMELEN, "%s:fake", device_get_nameunit(dev));
|
snprintf(c->name, CHN_NAMELEN, "%s:fake", device_get_nameunit(dev));
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
|
@ -320,7 +320,10 @@ chn_fmtchain(struct pcm_channel *c, u_int32_t *to)
|
|||||||
i = 0;
|
i = 0;
|
||||||
best = 0;
|
best = 0;
|
||||||
bestmax = 100;
|
bestmax = 100;
|
||||||
while (from[i] != 0) {
|
while (from[i] != 0)
|
||||||
|
i++;
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
c->feeder->desc->out = from[i];
|
c->feeder->desc->out = from[i];
|
||||||
try = NULL;
|
try = NULL;
|
||||||
max = 0;
|
max = 0;
|
||||||
@ -338,7 +341,6 @@ chn_fmtchain(struct pcm_channel *c, u_int32_t *to)
|
|||||||
try = try->source;
|
try = try->source;
|
||||||
feeder_destroy(del);
|
feeder_destroy(del);
|
||||||
}
|
}
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
if (best == 0)
|
if (best == 0)
|
||||||
return 0;
|
return 0;
|
||||||
@ -371,7 +373,16 @@ chn_fmtchain(struct pcm_channel *c, u_int32_t *to)
|
|||||||
printf("%s [%d]\n", try->class->name, try->desc->idx);
|
printf("%s [%d]\n", try->class->name, try->desc->idx);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return (c->direction == PCMDIR_REC)? best : c->feeder->desc->out;
|
if (c->direction == PCMDIR_REC) {
|
||||||
|
try = c->feeder;
|
||||||
|
while (try != NULL) {
|
||||||
|
if (try->desc->type == FEEDER_ROOT)
|
||||||
|
return try->desc->out;
|
||||||
|
try = try->source;
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
} else
|
||||||
|
return c->feeder->desc->out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -41,6 +41,7 @@ struct snd_mixer {
|
|||||||
int hwvol_muted;
|
int hwvol_muted;
|
||||||
int hwvol_mixer;
|
int hwvol_mixer;
|
||||||
int hwvol_step;
|
int hwvol_step;
|
||||||
|
device_t dev;
|
||||||
u_int32_t hwvol_mute_level;
|
u_int32_t hwvol_mute_level;
|
||||||
u_int32_t devs;
|
u_int32_t devs;
|
||||||
u_int32_t recdevs;
|
u_int32_t recdevs;
|
||||||
@ -60,6 +61,7 @@ static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
|
|||||||
[SOUND_MIXER_LINE] = 75,
|
[SOUND_MIXER_LINE] = 75,
|
||||||
[SOUND_MIXER_MIC] = 0,
|
[SOUND_MIXER_MIC] = 0,
|
||||||
[SOUND_MIXER_CD] = 75,
|
[SOUND_MIXER_CD] = 75,
|
||||||
|
[SOUND_MIXER_IGAIN] = 0,
|
||||||
[SOUND_MIXER_LINE1] = 75,
|
[SOUND_MIXER_LINE1] = 75,
|
||||||
[SOUND_MIXER_VIDEO] = 75,
|
[SOUND_MIXER_VIDEO] = 75,
|
||||||
[SOUND_MIXER_RECLEV] = 0,
|
[SOUND_MIXER_RECLEV] = 0,
|
||||||
@ -112,6 +114,7 @@ mixer_lookup(char *devname)
|
|||||||
static int
|
static int
|
||||||
mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
|
mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
|
||||||
{
|
{
|
||||||
|
struct snddev_info *d;
|
||||||
unsigned l, r;
|
unsigned l, r;
|
||||||
int v;
|
int v;
|
||||||
|
|
||||||
@ -121,9 +124,34 @@ mixer_set(struct snd_mixer *mixer, unsigned dev, unsigned lev)
|
|||||||
l = min((lev & 0x00ff), 100);
|
l = min((lev & 0x00ff), 100);
|
||||||
r = min(((lev & 0xff00) >> 8), 100);
|
r = min(((lev & 0xff00) >> 8), 100);
|
||||||
|
|
||||||
|
d = device_get_softc(mixer->dev);
|
||||||
|
if (dev == SOUND_MIXER_PCM && d &&
|
||||||
|
(d->flags & SD_F_SOFTVOL)) {
|
||||||
|
struct snddev_channel *sce;
|
||||||
|
struct pcm_channel *ch;
|
||||||
|
#ifdef USING_MUTEX
|
||||||
|
int locked = (mixer->lock && mtx_owned((struct mtx *)(mixer->lock))) ? 1 : 0;
|
||||||
|
|
||||||
|
if (locked)
|
||||||
|
snd_mtxunlock(mixer->lock);
|
||||||
|
#endif
|
||||||
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
|
ch = sce->channel;
|
||||||
|
CHN_LOCK(ch);
|
||||||
|
if (ch->direction == PCMDIR_PLAY &&
|
||||||
|
(ch->feederflags & (1 << FEEDER_VOLUME)))
|
||||||
|
chn_setvolume(ch, l, r);
|
||||||
|
CHN_UNLOCK(ch);
|
||||||
|
}
|
||||||
|
#ifdef USING_MUTEX
|
||||||
|
if (locked)
|
||||||
|
snd_mtxlock(mixer->lock);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
v = MIXER_SET(mixer, dev, l, r);
|
v = MIXER_SET(mixer, dev, l, r);
|
||||||
if (v < 0)
|
if (v < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
mixer->level[dev] = l | (r << 8);
|
mixer->level[dev] = l | (r << 8);
|
||||||
return 0;
|
return 0;
|
||||||
@ -156,6 +184,9 @@ mixer_getrecsrc(struct snd_mixer *mixer)
|
|||||||
void
|
void
|
||||||
mix_setdevs(struct snd_mixer *m, u_int32_t v)
|
mix_setdevs(struct snd_mixer *m, u_int32_t v)
|
||||||
{
|
{
|
||||||
|
struct snddev_info *d = device_get_softc(m->dev);
|
||||||
|
if (d && (d->flags & SD_F_SOFTVOL))
|
||||||
|
v |= SOUND_MASK_PCM;
|
||||||
m->devs = v;
|
m->devs = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,6 +229,7 @@ mixer_init(device_t dev, kobj_class_t cls, void *devinfo)
|
|||||||
m->type = cls->name;
|
m->type = cls->name;
|
||||||
m->devinfo = devinfo;
|
m->devinfo = devinfo;
|
||||||
m->busy = 0;
|
m->busy = 0;
|
||||||
|
m->dev = dev;
|
||||||
|
|
||||||
if (MIXER_INIT(m))
|
if (MIXER_INIT(m))
|
||||||
goto bad;
|
goto bad;
|
||||||
@ -397,16 +429,13 @@ static int
|
|||||||
mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
mixer_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
struct snd_mixer *m;
|
struct snd_mixer *m;
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
m = i_dev->si_drv1;
|
m = i_dev->si_drv1;
|
||||||
s = spltty();
|
|
||||||
snd_mtxlock(m->lock);
|
snd_mtxlock(m->lock);
|
||||||
|
|
||||||
m->busy++;
|
m->busy++;
|
||||||
|
|
||||||
snd_mtxunlock(m->lock);
|
snd_mtxunlock(m->lock);
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -414,21 +443,17 @@ static int
|
|||||||
mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
mixer_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
struct snd_mixer *m;
|
struct snd_mixer *m;
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
m = i_dev->si_drv1;
|
m = i_dev->si_drv1;
|
||||||
s = spltty();
|
|
||||||
snd_mtxlock(m->lock);
|
snd_mtxlock(m->lock);
|
||||||
|
|
||||||
if (!m->busy) {
|
if (!m->busy) {
|
||||||
snd_mtxunlock(m->lock);
|
snd_mtxunlock(m->lock);
|
||||||
splx(s);
|
|
||||||
return EBADF;
|
return EBADF;
|
||||||
}
|
}
|
||||||
m->busy--;
|
m->busy--;
|
||||||
|
|
||||||
snd_mtxunlock(m->lock);
|
snd_mtxunlock(m->lock);
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,15 +461,13 @@ int
|
|||||||
mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
|
mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
struct snd_mixer *m;
|
struct snd_mixer *m;
|
||||||
intrmask_t s;
|
|
||||||
int ret, *arg_i = (int *)arg;
|
int ret, *arg_i = (int *)arg;
|
||||||
int v = -1, j = cmd & 0xff;
|
int v = -1, j = cmd & 0xff;
|
||||||
|
|
||||||
m = i_dev->si_drv1;
|
m = i_dev->si_drv1;
|
||||||
if (!m->busy)
|
if (mode != -1 && !m->busy)
|
||||||
return EBADF;
|
return EBADF;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
snd_mtxlock(m->lock);
|
snd_mtxlock(m->lock);
|
||||||
if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
|
if ((cmd & MIXER_WRITE(0)) == MIXER_WRITE(0)) {
|
||||||
if (j == SOUND_MIXER_RECSRC)
|
if (j == SOUND_MIXER_RECSRC)
|
||||||
@ -452,7 +475,6 @@ mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread
|
|||||||
else
|
else
|
||||||
ret = mixer_set(m, j, *arg_i);
|
ret = mixer_set(m, j, *arg_i);
|
||||||
snd_mtxunlock(m->lock);
|
snd_mtxunlock(m->lock);
|
||||||
splx(s);
|
|
||||||
return (ret == 0)? 0 : ENXIO;
|
return (ret == 0)? 0 : ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,7 +502,6 @@ mixer_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struct thread
|
|||||||
return (v != -1)? 0 : ENXIO;
|
return (v != -1)? 0 : ENXIO;
|
||||||
}
|
}
|
||||||
snd_mtxunlock(m->lock);
|
snd_mtxunlock(m->lock);
|
||||||
splx(s);
|
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -495,7 +516,7 @@ mixer_clone(void *arg, struct ucred *cred, char *name, int namelen,
|
|||||||
return;
|
return;
|
||||||
if (strcmp(name, "mixer") == 0) {
|
if (strcmp(name, "mixer") == 0) {
|
||||||
sd = devclass_get_softc(pcm_devclass, snd_unit);
|
sd = devclass_get_softc(pcm_devclass, snd_unit);
|
||||||
if (sd != NULL) {
|
if (sd != NULL && sd->mixer_dev != NULL) {
|
||||||
*dev = sd->mixer_dev;
|
*dev = sd->mixer_dev;
|
||||||
dev_ref(*dev);
|
dev_ref(*dev);
|
||||||
}
|
}
|
||||||
|
@ -84,20 +84,17 @@ static int sndstat_prepare(struct sbuf *s);
|
|||||||
static int
|
static int
|
||||||
sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
|
sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
int error, verbose;
|
int error, verbose;
|
||||||
|
|
||||||
verbose = sndstat_verbose;
|
verbose = sndstat_verbose;
|
||||||
error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
|
error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req);
|
||||||
if (error == 0 && req->newptr != NULL) {
|
if (error == 0 && req->newptr != NULL) {
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (verbose < 0 || verbose > 3)
|
if (verbose < 0 || verbose > 3)
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
else
|
else
|
||||||
sndstat_verbose = verbose;
|
sndstat_verbose = verbose;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -107,19 +104,15 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
|
|||||||
static int
|
static int
|
||||||
sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (sndstat_isopen) {
|
if (sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
sndstat_isopen = 1;
|
sndstat_isopen = 1;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
|
if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) {
|
||||||
error = ENXIO;
|
error = ENXIO;
|
||||||
goto out;
|
goto out;
|
||||||
@ -128,11 +121,9 @@ sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
error = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
|
error = (sndstat_prepare(&sndstat_sbuf) > 0) ? 0 : ENOMEM;
|
||||||
out:
|
out:
|
||||||
if (error) {
|
if (error) {
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
sndstat_isopen = 0;
|
sndstat_isopen = 0;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
}
|
}
|
||||||
return (error);
|
return (error);
|
||||||
}
|
}
|
||||||
@ -140,34 +131,26 @@ sndstat_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
|||||||
static int
|
static int
|
||||||
sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
sndstat_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (!sndstat_isopen) {
|
if (!sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBADF;
|
return EBADF;
|
||||||
}
|
}
|
||||||
sbuf_delete(&sndstat_sbuf);
|
sbuf_delete(&sndstat_sbuf);
|
||||||
sndstat_isopen = 0;
|
sndstat_isopen = 0;
|
||||||
|
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
|
sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
int l, err;
|
int l, err;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (!sndstat_isopen) {
|
if (!sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBADF;
|
return EBADF;
|
||||||
}
|
}
|
||||||
l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
|
l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
|
||||||
@ -175,7 +158,6 @@ sndstat_read(struct cdev *i_dev, struct uio *buf, int flag)
|
|||||||
sndstat_bufptr += l;
|
sndstat_bufptr += l;
|
||||||
|
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,10 +176,35 @@ sndstat_find(int type, int unit)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sndstat_acquire(void)
|
||||||
|
{
|
||||||
|
sx_xlock(&sndstat_lock);
|
||||||
|
if (sndstat_isopen) {
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
sndstat_isopen = 1;
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
sndstat_release(void)
|
||||||
|
{
|
||||||
|
sx_xlock(&sndstat_lock);
|
||||||
|
if (!sndstat_isopen) {
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return EBADF;
|
||||||
|
}
|
||||||
|
sndstat_isopen = 0;
|
||||||
|
sx_xunlock(&sndstat_lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
sndstat_register(device_t dev, char *str, sndstat_handler handler)
|
sndstat_register(device_t dev, char *str, sndstat_handler handler)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
struct sndstat_entry *ent;
|
struct sndstat_entry *ent;
|
||||||
const char *devtype;
|
const char *devtype;
|
||||||
int type, unit;
|
int type, unit;
|
||||||
@ -228,14 +235,12 @@ sndstat_register(device_t dev, char *str, sndstat_handler handler)
|
|||||||
ent->unit = unit;
|
ent->unit = unit;
|
||||||
ent->handler = handler;
|
ent->handler = handler;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
|
SLIST_INSERT_HEAD(&sndstat_devlist, ent, link);
|
||||||
if (type == SS_TYPE_MODULE)
|
if (type == SS_TYPE_MODULE)
|
||||||
sndstat_files++;
|
sndstat_files++;
|
||||||
sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
|
sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -249,23 +254,19 @@ sndstat_registerfile(char *str)
|
|||||||
int
|
int
|
||||||
sndstat_unregister(device_t dev)
|
sndstat_unregister(device_t dev)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
struct sndstat_entry *ent;
|
struct sndstat_entry *ent;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
||||||
if (ent->dev == dev) {
|
if (ent->dev == dev) {
|
||||||
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
free(ent, M_DEVBUF);
|
free(ent, M_DEVBUF);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -273,24 +274,20 @@ sndstat_unregister(device_t dev)
|
|||||||
int
|
int
|
||||||
sndstat_unregisterfile(char *str)
|
sndstat_unregisterfile(char *str)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
struct sndstat_entry *ent;
|
struct sndstat_entry *ent;
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
SLIST_FOREACH(ent, &sndstat_devlist, link) {
|
||||||
if (ent->dev == NULL && ent->str == str) {
|
if (ent->dev == NULL && ent->str == str) {
|
||||||
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link);
|
||||||
sndstat_files--;
|
sndstat_files--;
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
free(ent, M_DEVBUF);
|
free(ent, M_DEVBUF);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
|
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
}
|
}
|
||||||
@ -353,13 +350,9 @@ sndstat_init(void)
|
|||||||
static int
|
static int
|
||||||
sndstat_uninit(void)
|
sndstat_uninit(void)
|
||||||
{
|
{
|
||||||
intrmask_t s;
|
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
sx_xlock(&sndstat_lock);
|
sx_xlock(&sndstat_lock);
|
||||||
if (sndstat_isopen) {
|
if (sndstat_isopen) {
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
splx(s);
|
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,18 +360,11 @@ sndstat_uninit(void)
|
|||||||
destroy_dev(sndstat_dev);
|
destroy_dev(sndstat_dev);
|
||||||
sndstat_dev = 0;
|
sndstat_dev = 0;
|
||||||
|
|
||||||
splx(s);
|
|
||||||
sx_xunlock(&sndstat_lock);
|
sx_xunlock(&sndstat_lock);
|
||||||
sx_destroy(&sndstat_lock);
|
sx_destroy(&sndstat_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
|
||||||
sndstat_busy(void)
|
|
||||||
{
|
|
||||||
return (sndstat_isopen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sndstat_sysinit(void *p)
|
sndstat_sysinit(void *p)
|
||||||
{
|
{
|
||||||
|
@ -166,8 +166,6 @@ pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid, int chnum)
|
|||||||
struct snddev_channel *sce;
|
struct snddev_channel *sce;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
snd_mtxassert(d->lock);
|
|
||||||
|
|
||||||
/* scan for a free channel */
|
/* scan for a free channel */
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
c = sce->channel;
|
c = sce->channel;
|
||||||
@ -189,7 +187,8 @@ pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid, int chnum)
|
|||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
c = sce->channel;
|
c = sce->channel;
|
||||||
CHN_LOCK(c);
|
CHN_LOCK(c);
|
||||||
if (!SLIST_EMPTY(&c->children)) {
|
if ((c->flags & CHN_F_HAS_VCHAN) &&
|
||||||
|
!SLIST_EMPTY(&c->children)) {
|
||||||
err = vchan_create(c);
|
err = vchan_create(c);
|
||||||
CHN_UNLOCK(c);
|
CHN_UNLOCK(c);
|
||||||
if (!err)
|
if (!err)
|
||||||
@ -246,45 +245,64 @@ pcm_inprog(struct snddev_info *d, int delta)
|
|||||||
static void
|
static void
|
||||||
pcm_setmaxautovchans(struct snddev_info *d, int num)
|
pcm_setmaxautovchans(struct snddev_info *d, int num)
|
||||||
{
|
{
|
||||||
struct pcm_channel *c;
|
struct pcm_channel *c, *ch;
|
||||||
struct snddev_channel *sce;
|
struct snddev_channel *sce;
|
||||||
int err, done;
|
int err, done;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX WOAH... NEED SUPER CLEANUP!!!
|
||||||
|
* Robust, yet confusing. Understanding these will
|
||||||
|
* cause your brain spinning like a Doki Doki Dynamo.
|
||||||
|
*/
|
||||||
if (num > 0 && d->vchancount == 0) {
|
if (num > 0 && d->vchancount == 0) {
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
c = sce->channel;
|
c = sce->channel;
|
||||||
CHN_LOCK(c);
|
CHN_LOCK(c);
|
||||||
if ((c->direction == PCMDIR_PLAY) && !(c->flags & CHN_F_BUSY)) {
|
if ((c->direction == PCMDIR_PLAY) &&
|
||||||
|
!(c->flags & CHN_F_BUSY) &&
|
||||||
|
SLIST_EMPTY(&c->children)) {
|
||||||
c->flags |= CHN_F_BUSY;
|
c->flags |= CHN_F_BUSY;
|
||||||
err = vchan_create(c);
|
err = vchan_create(c);
|
||||||
if (err) {
|
if (err) {
|
||||||
c->flags &= ~CHN_F_BUSY;
|
c->flags &= ~CHN_F_BUSY;
|
||||||
CHN_UNLOCK(c);
|
|
||||||
device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err);
|
device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err);
|
||||||
} else
|
}
|
||||||
CHN_UNLOCK(c);
|
CHN_UNLOCK(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CHN_UNLOCK(c);
|
CHN_UNLOCK(c);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
if (num == 0 && d->vchancount > 0) {
|
if (num == 0 && d->vchancount > 0) {
|
||||||
done = 0;
|
/*
|
||||||
while (!done) {
|
* XXX Keep retrying...
|
||||||
done = 1;
|
*/
|
||||||
|
for (done = 0; done < 1024; done++) {
|
||||||
|
ch = NULL;
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
c = sce->channel;
|
c = sce->channel;
|
||||||
if ((c->flags & CHN_F_VIRTUAL) && !(c->flags & CHN_F_BUSY)) {
|
CHN_LOCK(c);
|
||||||
done = 0;
|
if (c->direction == PCMDIR_PLAY &&
|
||||||
|
!(c->flags & CHN_F_BUSY) &&
|
||||||
|
(c->flags & CHN_F_VIRTUAL)) {
|
||||||
|
ch = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CHN_UNLOCK(c);
|
||||||
|
}
|
||||||
|
if (ch != NULL) {
|
||||||
|
CHN_UNLOCK(ch);
|
||||||
snd_mtxlock(d->lock);
|
snd_mtxlock(d->lock);
|
||||||
err = vchan_destroy(c);
|
err = vchan_destroy(ch);
|
||||||
snd_mtxunlock(d->lock);
|
|
||||||
if (err)
|
if (err)
|
||||||
device_printf(d->dev, "vchan_destroy(%s) == %d\n", c->name, err);
|
device_printf(d->dev, "vchan_destroy(%s) == %d\n",
|
||||||
break; /* restart */
|
ch->name, err);
|
||||||
}
|
snd_mtxunlock(d->lock);
|
||||||
}
|
} else
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +345,11 @@ sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS)
|
|||||||
d = devclass_get_softc(pcm_devclass, i);
|
d = devclass_get_softc(pcm_devclass, i);
|
||||||
if (!d)
|
if (!d)
|
||||||
continue;
|
continue;
|
||||||
|
if (d->flags & SD_F_AUTOVCHAN) {
|
||||||
|
if (pcm_inprog(d, 1) == 1)
|
||||||
pcm_setmaxautovchans(d, v);
|
pcm_setmaxautovchans(d, v);
|
||||||
|
pcm_inprog(d, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
snd_maxautovchans = v;
|
snd_maxautovchans = v;
|
||||||
@ -449,12 +471,38 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
|
|||||||
if (SLIST_EMPTY(&d->channels)) {
|
if (SLIST_EMPTY(&d->channels)) {
|
||||||
SLIST_INSERT_HEAD(&d->channels, sce, link);
|
SLIST_INSERT_HEAD(&d->channels, sce, link);
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
|
* Micro optimization, channel ordering:
|
||||||
|
* hw,hw,hw,vch,vch,vch,rec
|
||||||
|
*/
|
||||||
after = NULL;
|
after = NULL;
|
||||||
|
if (ch->flags & CHN_F_VIRTUAL) {
|
||||||
|
/* virtual channel to the end */
|
||||||
|
SLIST_FOREACH(tmp, &d->channels, link) {
|
||||||
|
if (tmp->channel->direction == PCMDIR_REC)
|
||||||
|
break;
|
||||||
|
after = tmp;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ch->direction == PCMDIR_REC) {
|
||||||
SLIST_FOREACH(tmp, &d->channels, link) {
|
SLIST_FOREACH(tmp, &d->channels, link) {
|
||||||
after = tmp;
|
after = tmp;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
SLIST_FOREACH(tmp, &d->channels, link) {
|
||||||
|
if (tmp->channel->direction == PCMDIR_REC)
|
||||||
|
break;
|
||||||
|
if (!(tmp->channel->flags & CHN_F_VIRTUAL))
|
||||||
|
after = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (after == NULL) {
|
||||||
|
SLIST_INSERT_HEAD(&d->channels, sce, link);
|
||||||
|
} else {
|
||||||
SLIST_INSERT_AFTER(after, sce, link);
|
SLIST_INSERT_AFTER(after, sce, link);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
sce->dsp_devt= make_dev(&dsp_cdevsw,
|
sce->dsp_devt= make_dev(&dsp_cdevsw,
|
||||||
PCMMKMINOR(device, SND_DEV_DSP, sce->chan_num),
|
PCMMKMINOR(device, SND_DEV_DSP, sce->chan_num),
|
||||||
@ -506,10 +554,10 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
|
|||||||
gotit:
|
gotit:
|
||||||
SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
|
SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
|
||||||
|
|
||||||
if (ch->direction == PCMDIR_REC)
|
if (ch->flags & CHN_F_VIRTUAL)
|
||||||
d->reccount--;
|
|
||||||
else if (ch->flags & CHN_F_VIRTUAL)
|
|
||||||
d->vchancount--;
|
d->vchancount--;
|
||||||
|
else if (ch->direction == PCMDIR_REC)
|
||||||
|
d->reccount--;
|
||||||
else
|
else
|
||||||
d->playcount--;
|
d->playcount--;
|
||||||
|
|
||||||
@ -654,7 +702,14 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
|
|||||||
|
|
||||||
d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
|
d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* d->flags should be cleared by the allocator of the softc.
|
||||||
|
* We cannot clear this field here because several devices set
|
||||||
|
* this flag before calling pcm_register().
|
||||||
|
*/
|
||||||
d->flags = 0;
|
d->flags = 0;
|
||||||
|
#endif
|
||||||
d->dev = dev;
|
d->dev = dev;
|
||||||
d->devinfo = devinfo;
|
d->devinfo = devinfo;
|
||||||
d->devcount = 0;
|
d->devcount = 0;
|
||||||
@ -663,7 +718,6 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
|
|||||||
d->vchancount = 0;
|
d->vchancount = 0;
|
||||||
d->inprog = 0;
|
d->inprog = 0;
|
||||||
|
|
||||||
SLIST_INIT(&d->channels);
|
|
||||||
SLIST_INIT(&d->channels);
|
SLIST_INIT(&d->channels);
|
||||||
|
|
||||||
if (((numplay == 0) || (numrec == 0)) && (numplay != numrec))
|
if (((numplay == 0) || (numrec == 0)) && (numplay != numrec))
|
||||||
@ -684,10 +738,10 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
|
|||||||
SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
||||||
OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "");
|
OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, "");
|
||||||
#endif
|
#endif
|
||||||
if (numplay > 0)
|
if (numplay > 0) {
|
||||||
vchan_initsys(dev);
|
vchan_initsys(dev);
|
||||||
if (numplay == 1)
|
|
||||||
d->flags |= SD_F_AUTOVCHAN;
|
d->flags |= SD_F_AUTOVCHAN;
|
||||||
|
}
|
||||||
|
|
||||||
sndstat_register(dev, d->status, sndstat_prepare_pcm);
|
sndstat_register(dev, d->status, sndstat_prepare_pcm);
|
||||||
return 0;
|
return 0;
|
||||||
@ -703,24 +757,25 @@ pcm_unregister(device_t dev)
|
|||||||
struct snddev_channel *sce;
|
struct snddev_channel *sce;
|
||||||
struct pcm_channel *ch;
|
struct pcm_channel *ch;
|
||||||
|
|
||||||
|
if (sndstat_acquire() != 0) {
|
||||||
|
device_printf(dev, "unregister: sndstat busy\n");
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
snd_mtxlock(d->lock);
|
snd_mtxlock(d->lock);
|
||||||
if (d->inprog) {
|
if (d->inprog) {
|
||||||
device_printf(dev, "unregister: operation in progress\n");
|
device_printf(dev, "unregister: operation in progress\n");
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
|
sndstat_release();
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
if (sndstat_busy() != 0) {
|
|
||||||
device_printf(dev, "unregister: sndstat busy\n");
|
|
||||||
snd_mtxunlock(d->lock);
|
|
||||||
return EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
ch = sce->channel;
|
ch = sce->channel;
|
||||||
if (ch->refcount > 0) {
|
if (ch->refcount > 0) {
|
||||||
device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid);
|
device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid);
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
|
sndstat_release();
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -728,6 +783,7 @@ pcm_unregister(device_t dev)
|
|||||||
if (mixer_uninit(dev)) {
|
if (mixer_uninit(dev)) {
|
||||||
device_printf(dev, "unregister: mixer busy\n");
|
device_printf(dev, "unregister: mixer busy\n");
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
|
sndstat_release();
|
||||||
return EBUSY;
|
return EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -752,9 +808,10 @@ pcm_unregister(device_t dev)
|
|||||||
chn_kill(d->fakechan);
|
chn_kill(d->fakechan);
|
||||||
fkchan_kill(d->fakechan);
|
fkchan_kill(d->fakechan);
|
||||||
|
|
||||||
sndstat_unregister(dev);
|
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
snd_mtxfree(d->lock);
|
snd_mtxfree(d->lock);
|
||||||
|
sndstat_unregister(dev);
|
||||||
|
sndstat_release();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,9 +882,25 @@ sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
|
|||||||
if (c->direction == PCMDIR_REC)
|
if (c->direction == PCMDIR_REC)
|
||||||
sbuf_printf(s, "overruns %d, hfree %d, sfree %d",
|
sbuf_printf(s, "overruns %d, hfree %d, sfree %d",
|
||||||
c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft));
|
c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft));
|
||||||
|
#if 0
|
||||||
|
sbuf_printf(s, "overruns %d, hfree %d, sfree %d [b:%d/%d/%d|bs:%d/%d/%d]",
|
||||||
|
c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft),
|
||||||
|
sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard),
|
||||||
|
sndbuf_getblkcnt(c->bufhard),
|
||||||
|
sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft),
|
||||||
|
sndbuf_getblkcnt(c->bufsoft));
|
||||||
|
#endif
|
||||||
else
|
else
|
||||||
sbuf_printf(s, "underruns %d, ready %d",
|
sbuf_printf(s, "underruns %d, ready %d",
|
||||||
c->xruns, sndbuf_getready(c->bufsoft));
|
c->xruns, sndbuf_getready(c->bufsoft));
|
||||||
|
#if 0
|
||||||
|
sbuf_printf(s, "underruns %d, ready %d [b:%d/%d/%d|bs:%d/%d/%d]",
|
||||||
|
c->xruns, sndbuf_getready(c->bufsoft),
|
||||||
|
sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard),
|
||||||
|
sndbuf_getblkcnt(c->bufhard),
|
||||||
|
sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft),
|
||||||
|
sndbuf_getblkcnt(c->bufsoft));
|
||||||
|
#endif
|
||||||
sbuf_printf(s, "\n\t");
|
sbuf_printf(s, "\n\t");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -842,7 +915,8 @@ sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose)
|
|||||||
sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
|
sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out);
|
||||||
if (f->desc->type == FEEDER_RATE)
|
if (f->desc->type == FEEDER_RATE)
|
||||||
sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
|
sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST));
|
||||||
if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER)
|
if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER ||
|
||||||
|
f->desc->type == FEEDER_VOLUME)
|
||||||
sbuf_printf(s, "(0x%08x)", f->desc->out);
|
sbuf_printf(s, "(0x%08x)", f->desc->out);
|
||||||
sbuf_printf(s, " -> ");
|
sbuf_printf(s, " -> ");
|
||||||
f = f->parent;
|
f = f->parent;
|
||||||
@ -865,26 +939,31 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
|
|||||||
struct snddev_info *d;
|
struct snddev_info *d;
|
||||||
struct snddev_channel *sce;
|
struct snddev_channel *sce;
|
||||||
struct pcm_channel *c;
|
struct pcm_channel *c;
|
||||||
int err, newcnt, cnt, busy;
|
int err, newcnt, cnt;
|
||||||
int x;
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX WOAH... NEED SUPER CLEANUP!!!
|
||||||
|
* Robust, yet confusing. Understanding these will
|
||||||
|
* cause your brain spinning like a Doki Doki Dynamo.
|
||||||
|
*/
|
||||||
d = oidp->oid_arg1;
|
d = oidp->oid_arg1;
|
||||||
|
|
||||||
x = pcm_inprog(d, 1);
|
if (!(d->flags & SD_F_AUTOVCHAN)) {
|
||||||
if (x != 1) {
|
|
||||||
pcm_inprog(d, -1);
|
pcm_inprog(d, -1);
|
||||||
return EINPROGRESS;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
busy = 0;
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
c = sce->channel;
|
c = sce->channel;
|
||||||
CHN_LOCK(c);
|
CHN_LOCK(c);
|
||||||
if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) {
|
if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) {
|
||||||
cnt++;
|
cnt++;
|
||||||
if (c->flags & CHN_F_BUSY)
|
if (req->newptr != NULL && c->flags & CHN_F_BUSY) {
|
||||||
busy++;
|
/* Better safe than sorry */
|
||||||
|
CHN_UNLOCK(c);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CHN_UNLOCK(c);
|
CHN_UNLOCK(c);
|
||||||
}
|
}
|
||||||
@ -895,9 +974,12 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
|
|||||||
|
|
||||||
if (err == 0 && req->newptr != NULL) {
|
if (err == 0 && req->newptr != NULL) {
|
||||||
|
|
||||||
if (newcnt < 0 || newcnt > SND_MAXVCHANS) {
|
if (newcnt < 0 || newcnt > SND_MAXVCHANS)
|
||||||
pcm_inprog(d, -1);
|
|
||||||
return E2BIG;
|
return E2BIG;
|
||||||
|
|
||||||
|
if (pcm_inprog(d, 1) != 1) {
|
||||||
|
pcm_inprog(d, -1);
|
||||||
|
return EINPROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newcnt > cnt) {
|
if (newcnt > cnt) {
|
||||||
@ -936,22 +1018,15 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
|
|||||||
if (err == 0)
|
if (err == 0)
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
if (SLIST_EMPTY(&c->children))
|
|
||||||
c->flags &= ~CHN_F_BUSY;
|
|
||||||
CHN_UNLOCK(c);
|
CHN_UNLOCK(c);
|
||||||
} else if (newcnt < cnt) {
|
} else if (newcnt < cnt) {
|
||||||
if (busy > newcnt) {
|
|
||||||
printf("cnt %d, newcnt %d, busy %d\n", cnt, newcnt, busy);
|
|
||||||
pcm_inprog(d, -1);
|
|
||||||
return EBUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_mtxlock(d->lock);
|
snd_mtxlock(d->lock);
|
||||||
while (err == 0 && newcnt < cnt) {
|
while (err == 0 && newcnt < cnt) {
|
||||||
SLIST_FOREACH(sce, &d->channels, link) {
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
c = sce->channel;
|
c = sce->channel;
|
||||||
CHN_LOCK(c);
|
CHN_LOCK(c);
|
||||||
if ((c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL)
|
if (c->direction == PCMDIR_PLAY &&
|
||||||
|
(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL)
|
||||||
goto remok;
|
goto remok;
|
||||||
|
|
||||||
CHN_UNLOCK(c);
|
CHN_UNLOCK(c);
|
||||||
@ -967,8 +1042,8 @@ sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS)
|
|||||||
}
|
}
|
||||||
snd_mtxunlock(d->lock);
|
snd_mtxunlock(d->lock);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
pcm_inprog(d, -1);
|
pcm_inprog(d, -1);
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -131,6 +131,7 @@ currently minor = (channel << 16) + (unit << 4) + dev
|
|||||||
|
|
||||||
#define SD_F_SIMPLEX 0x00000001
|
#define SD_F_SIMPLEX 0x00000001
|
||||||
#define SD_F_AUTOVCHAN 0x00000002
|
#define SD_F_AUTOVCHAN 0x00000002
|
||||||
|
#define SD_F_SOFTVOL 0x00000004
|
||||||
#define SD_F_PRIO_RD 0x10000000
|
#define SD_F_PRIO_RD 0x10000000
|
||||||
#define SD_F_PRIO_WR 0x20000000
|
#define SD_F_PRIO_WR 0x20000000
|
||||||
#define SD_F_PRIO_SET (SD_F_PRIO_RD | SD_F_PRIO_WR)
|
#define SD_F_PRIO_SET (SD_F_PRIO_RD | SD_F_PRIO_WR)
|
||||||
@ -144,10 +145,13 @@ currently minor = (channel << 16) + (unit << 4) + dev
|
|||||||
|
|
||||||
/* make figuring out what a format is easier. got AFMT_STEREO already */
|
/* make figuring out what a format is easier. got AFMT_STEREO already */
|
||||||
#define AFMT_32BIT (AFMT_S32_LE | AFMT_S32_BE | AFMT_U32_LE | AFMT_U32_BE)
|
#define AFMT_32BIT (AFMT_S32_LE | AFMT_S32_BE | AFMT_U32_LE | AFMT_U32_BE)
|
||||||
|
#define AFMT_24BIT (AFMT_S24_LE | AFMT_S24_BE | AFMT_U24_LE | AFMT_U24_BE)
|
||||||
#define AFMT_16BIT (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
|
#define AFMT_16BIT (AFMT_S16_LE | AFMT_S16_BE | AFMT_U16_LE | AFMT_U16_BE)
|
||||||
#define AFMT_8BIT (AFMT_U8 | AFMT_S8)
|
#define AFMT_8BIT (AFMT_MU_LAW | AFMT_A_LAW | AFMT_U8 | AFMT_S8)
|
||||||
#define AFMT_SIGNED (AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)
|
#define AFMT_SIGNED (AFMT_S32_LE | AFMT_S32_BE | AFMT_S24_LE | AFMT_S24_BE | \
|
||||||
#define AFMT_BIGENDIAN (AFMT_S16_BE | AFMT_U16_BE)
|
AFMT_S16_LE | AFMT_S16_BE | AFMT_S8)
|
||||||
|
#define AFMT_BIGENDIAN (AFMT_S32_BE | AFMT_U32_BE | AFMT_S24_BE | AFMT_U24_BE | \
|
||||||
|
AFMT_S16_BE | AFMT_U16_BE)
|
||||||
|
|
||||||
struct pcm_channel *fkchan_setup(device_t dev);
|
struct pcm_channel *fkchan_setup(device_t dev);
|
||||||
int fkchan_kill(struct pcm_channel *c);
|
int fkchan_kill(struct pcm_channel *c);
|
||||||
@ -235,11 +239,12 @@ void snd_mtxassert(void *m);
|
|||||||
int sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS);
|
int sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS);
|
||||||
|
|
||||||
typedef int (*sndstat_handler)(struct sbuf *s, device_t dev, int verbose);
|
typedef int (*sndstat_handler)(struct sbuf *s, device_t dev, int verbose);
|
||||||
|
int sndstat_acquire(void);
|
||||||
|
int sndstat_release(void);
|
||||||
int sndstat_register(device_t dev, char *str, sndstat_handler handler);
|
int sndstat_register(device_t dev, char *str, sndstat_handler handler);
|
||||||
int sndstat_registerfile(char *str);
|
int sndstat_registerfile(char *str);
|
||||||
int sndstat_unregister(device_t dev);
|
int sndstat_unregister(device_t dev);
|
||||||
int sndstat_unregisterfile(char *str);
|
int sndstat_unregisterfile(char *str);
|
||||||
int sndstat_busy(void);
|
|
||||||
|
|
||||||
#define SND_DECLARE_FILE(version) \
|
#define SND_DECLARE_FILE(version) \
|
||||||
_SND_DECLARE_FILE(__LINE__, version)
|
_SND_DECLARE_FILE(__LINE__, version)
|
||||||
|
@ -30,6 +30,14 @@
|
|||||||
|
|
||||||
SND_DECLARE_FILE("$FreeBSD$");
|
SND_DECLARE_FILE("$FreeBSD$");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default speed
|
||||||
|
*/
|
||||||
|
#define VCHAN_DEFAULT_SPEED 44100
|
||||||
|
|
||||||
|
extern int feeder_rate_ratemin;
|
||||||
|
extern int feeder_rate_ratemax;
|
||||||
|
|
||||||
struct vchinfo {
|
struct vchinfo {
|
||||||
u_int32_t spd, fmt, blksz, bps, run;
|
u_int32_t spd, fmt, blksz, bps, run;
|
||||||
struct pcm_channel *channel, *parent;
|
struct pcm_channel *channel, *parent;
|
||||||
@ -74,13 +82,21 @@ feed_vchan_s16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32
|
|||||||
struct snd_dbuf *src = source;
|
struct snd_dbuf *src = source;
|
||||||
struct pcmchan_children *cce;
|
struct pcmchan_children *cce;
|
||||||
struct pcm_channel *ch;
|
struct pcm_channel *ch;
|
||||||
|
uint32_t sz;
|
||||||
int16_t *tmp, *dst;
|
int16_t *tmp, *dst;
|
||||||
unsigned int cnt;
|
unsigned int cnt, rcnt = 0;
|
||||||
|
|
||||||
|
#if 0
|
||||||
if (sndbuf_getsize(src) < count)
|
if (sndbuf_getsize(src) < count)
|
||||||
panic("feed_vchan_s16(%s): tmp buffer size %d < count %d, flags = 0x%x",
|
panic("feed_vchan_s16(%s): tmp buffer size %d < count %d, flags = 0x%x",
|
||||||
c->name, sndbuf_getsize(src), count, c->flags);
|
c->name, sndbuf_getsize(src), count, c->flags);
|
||||||
|
#endif
|
||||||
|
sz = sndbuf_getsize(src);
|
||||||
|
if (sz < count)
|
||||||
|
count = sz;
|
||||||
count &= ~1;
|
count &= ~1;
|
||||||
|
if (count < 2)
|
||||||
|
return 0;
|
||||||
bzero(b, count);
|
bzero(b, count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -99,12 +115,14 @@ feed_vchan_s16(struct pcm_feeder *f, struct pcm_channel *c, u_int8_t *b, u_int32
|
|||||||
if (ch->flags & CHN_F_MAPPED)
|
if (ch->flags & CHN_F_MAPPED)
|
||||||
sndbuf_acquire(ch->bufsoft, NULL, sndbuf_getfree(ch->bufsoft));
|
sndbuf_acquire(ch->bufsoft, NULL, sndbuf_getfree(ch->bufsoft));
|
||||||
cnt = FEEDER_FEED(ch->feeder, ch, (u_int8_t *)tmp, count, ch->bufsoft);
|
cnt = FEEDER_FEED(ch->feeder, ch, (u_int8_t *)tmp, count, ch->bufsoft);
|
||||||
vchan_mix_s16(dst, tmp, cnt / 2);
|
vchan_mix_s16(dst, tmp, cnt >> 1);
|
||||||
|
if (cnt > rcnt)
|
||||||
|
rcnt = cnt;
|
||||||
}
|
}
|
||||||
CHN_UNLOCK(ch);
|
CHN_UNLOCK(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return rcnt & ~1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pcm_feederdesc feeder_vchan_s16_desc[] = {
|
static struct pcm_feederdesc feeder_vchan_s16_desc[] = {
|
||||||
@ -127,6 +145,8 @@ vchan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *c,
|
|||||||
|
|
||||||
KASSERT(dir == PCMDIR_PLAY, ("vchan_init: bad direction"));
|
KASSERT(dir == PCMDIR_PLAY, ("vchan_init: bad direction"));
|
||||||
ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
|
ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
|
||||||
|
if (!ch)
|
||||||
|
return NULL;
|
||||||
ch->parent = parent;
|
ch->parent = parent;
|
||||||
ch->channel = c;
|
ch->channel = c;
|
||||||
ch->fmt = AFMT_U8;
|
ch->fmt = AFMT_U8;
|
||||||
@ -154,11 +174,16 @@ vchan_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
ch->fmt = format;
|
ch->fmt = format;
|
||||||
ch->bps = 1;
|
ch->bps = 1;
|
||||||
ch->bps <<= (ch->fmt & AFMT_STEREO)? 1 : 0;
|
ch->bps <<= (ch->fmt & AFMT_STEREO)? 1 : 0;
|
||||||
ch->bps <<= (ch->fmt & AFMT_16BIT)? 1 : 0;
|
if (ch->fmt & AFMT_16BIT)
|
||||||
ch->bps <<= (ch->fmt & AFMT_32BIT)? 2 : 0;
|
ch->bps <<= 1;
|
||||||
|
else if (ch->fmt & AFMT_24BIT)
|
||||||
|
ch->bps *= 3;
|
||||||
|
else if (ch->fmt & AFMT_32BIT)
|
||||||
|
ch->bps <<= 2;
|
||||||
CHN_UNLOCK(channel);
|
CHN_UNLOCK(channel);
|
||||||
chn_notify(parent, CHN_N_FORMAT);
|
chn_notify(parent, CHN_N_FORMAT);
|
||||||
CHN_LOCK(channel);
|
CHN_LOCK(channel);
|
||||||
|
sndbuf_setfmt(channel->bufsoft, format);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +196,9 @@ vchan_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
|||||||
|
|
||||||
ch->spd = speed;
|
ch->spd = speed;
|
||||||
CHN_UNLOCK(channel);
|
CHN_UNLOCK(channel);
|
||||||
chn_notify(parent, CHN_N_RATE);
|
CHN_LOCK(parent);
|
||||||
|
speed = sndbuf_getspd(parent->bufsoft);
|
||||||
|
CHN_UNLOCK(parent);
|
||||||
CHN_LOCK(channel);
|
CHN_LOCK(channel);
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
@ -180,19 +207,21 @@ static int
|
|||||||
vchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
|
vchan_setblocksize(kobj_t obj, void *data, u_int32_t blocksize)
|
||||||
{
|
{
|
||||||
struct vchinfo *ch = data;
|
struct vchinfo *ch = data;
|
||||||
|
struct pcm_channel *channel = ch->channel;
|
||||||
struct pcm_channel *parent = ch->parent;
|
struct pcm_channel *parent = ch->parent;
|
||||||
/* struct pcm_channel *channel = ch->channel; */
|
/* struct pcm_channel *channel = ch->channel; */
|
||||||
int prate, crate;
|
int prate, crate;
|
||||||
|
|
||||||
ch->blksz = blocksize;
|
ch->blksz = blocksize;
|
||||||
/* CHN_UNLOCK(channel); */
|
/* CHN_UNLOCK(channel); */
|
||||||
|
sndbuf_setblksz(channel->bufhard, blocksize);
|
||||||
chn_notify(parent, CHN_N_BLOCKSIZE);
|
chn_notify(parent, CHN_N_BLOCKSIZE);
|
||||||
CHN_LOCK(parent);
|
CHN_LOCK(parent);
|
||||||
/* CHN_LOCK(channel); */
|
/* CHN_LOCK(channel); */
|
||||||
|
|
||||||
crate = ch->spd * ch->bps;
|
crate = ch->spd * ch->bps;
|
||||||
prate = sndbuf_getspd(parent->bufhard) * sndbuf_getbps(parent->bufhard);
|
prate = sndbuf_getspd(parent->bufsoft) * sndbuf_getbps(parent->bufsoft);
|
||||||
blocksize = sndbuf_getblksz(parent->bufhard);
|
blocksize = sndbuf_getblksz(parent->bufsoft);
|
||||||
CHN_UNLOCK(parent);
|
CHN_UNLOCK(parent);
|
||||||
blocksize *= prate;
|
blocksize *= prate;
|
||||||
blocksize /= crate;
|
blocksize /= crate;
|
||||||
@ -223,7 +252,7 @@ vchan_getcaps(kobj_t obj, void *data)
|
|||||||
{
|
{
|
||||||
struct vchinfo *ch = data;
|
struct vchinfo *ch = data;
|
||||||
|
|
||||||
ch->caps.minspeed = sndbuf_getspd(ch->parent->bufhard);
|
ch->caps.minspeed = sndbuf_getspd(ch->parent->bufsoft);
|
||||||
ch->caps.maxspeed = ch->caps.minspeed;
|
ch->caps.maxspeed = ch->caps.minspeed;
|
||||||
ch->caps.fmtlist = vchan_fmt;
|
ch->caps.fmtlist = vchan_fmt;
|
||||||
ch->caps.caps = 0;
|
ch->caps.caps = 0;
|
||||||
@ -243,6 +272,91 @@ static kobj_method_t vchan_methods[] = {
|
|||||||
};
|
};
|
||||||
CHANNEL_DECLARE(vchan);
|
CHANNEL_DECLARE(vchan);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* On the fly vchan rate settings
|
||||||
|
*/
|
||||||
|
#ifdef SND_DYNSYSCTL
|
||||||
|
static int
|
||||||
|
sysctl_hw_snd_vchanrate(SYSCTL_HANDLER_ARGS)
|
||||||
|
{
|
||||||
|
struct snddev_info *d;
|
||||||
|
struct snddev_channel *sce;
|
||||||
|
struct pcm_channel *c, *ch = NULL, *fake;
|
||||||
|
struct pcmchan_caps *caps;
|
||||||
|
int err = 0;
|
||||||
|
int newspd = 0;
|
||||||
|
|
||||||
|
d = oidp->oid_arg1;
|
||||||
|
if (!(d->flags & SD_F_AUTOVCHAN) || d->vchancount < 1)
|
||||||
|
return EINVAL;
|
||||||
|
SLIST_FOREACH(sce, &d->channels, link) {
|
||||||
|
c = sce->channel;
|
||||||
|
CHN_LOCK(c);
|
||||||
|
if (c->direction == PCMDIR_PLAY) {
|
||||||
|
if (c->flags & CHN_F_VIRTUAL) {
|
||||||
|
if (req->newptr != NULL &&
|
||||||
|
(c->flags & CHN_F_BUSY)) {
|
||||||
|
CHN_UNLOCK(c);
|
||||||
|
return EBUSY;
|
||||||
|
}
|
||||||
|
if (ch == NULL)
|
||||||
|
ch = c->parentchannel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHN_UNLOCK(c);
|
||||||
|
}
|
||||||
|
if (ch != NULL) {
|
||||||
|
CHN_LOCK(ch);
|
||||||
|
newspd = ch->speed;
|
||||||
|
CHN_UNLOCK(ch);
|
||||||
|
}
|
||||||
|
err = sysctl_handle_int(oidp, &newspd, sizeof(newspd), req);
|
||||||
|
if (err == 0 && req->newptr != NULL) {
|
||||||
|
if (ch == NULL || newspd < 1 ||
|
||||||
|
newspd < feeder_rate_ratemin ||
|
||||||
|
newspd > feeder_rate_ratemax)
|
||||||
|
return EINVAL;
|
||||||
|
if (pcm_inprog(d, 1) != 1) {
|
||||||
|
pcm_inprog(d, -1);
|
||||||
|
return EINPROGRESS;
|
||||||
|
}
|
||||||
|
CHN_LOCK(ch);
|
||||||
|
caps = chn_getcaps(ch);
|
||||||
|
if (caps == NULL || newspd < caps->minspeed ||
|
||||||
|
newspd > caps->maxspeed) {
|
||||||
|
CHN_UNLOCK(ch);
|
||||||
|
pcm_inprog(d, -1);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
if (newspd != ch->speed) {
|
||||||
|
err = chn_setspeed(ch, newspd);
|
||||||
|
/*
|
||||||
|
* Try to avoid FEEDER_RATE on parent channel if the
|
||||||
|
* requested value is not supported by the hardware.
|
||||||
|
*/
|
||||||
|
if (!err && (ch->feederflags & (1 << FEEDER_RATE))) {
|
||||||
|
newspd = sndbuf_getspd(ch->bufhard);
|
||||||
|
err = chn_setspeed(ch, newspd);
|
||||||
|
}
|
||||||
|
CHN_UNLOCK(ch);
|
||||||
|
if (err == 0) {
|
||||||
|
fake = pcm_getfakechan(d);
|
||||||
|
if (fake != NULL) {
|
||||||
|
CHN_LOCK(fake);
|
||||||
|
fake->speed = newspd;
|
||||||
|
CHN_UNLOCK(fake);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
CHN_UNLOCK(ch);
|
||||||
|
pcm_inprog(d, -1);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* virtual channel interface */
|
/* virtual channel interface */
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -250,9 +364,13 @@ vchan_create(struct pcm_channel *parent)
|
|||||||
{
|
{
|
||||||
struct snddev_info *d = parent->parentsnddev;
|
struct snddev_info *d = parent->parentsnddev;
|
||||||
struct pcmchan_children *pce;
|
struct pcmchan_children *pce;
|
||||||
struct pcm_channel *child;
|
struct pcm_channel *child, *fake;
|
||||||
struct pcmchan_caps *parent_caps;
|
struct pcmchan_caps *parent_caps;
|
||||||
int err, first, speed;
|
int err, first, speed = 0;
|
||||||
|
|
||||||
|
if (!(parent->flags & CHN_F_BUSY))
|
||||||
|
return EBUSY;
|
||||||
|
|
||||||
|
|
||||||
CHN_UNLOCK(parent);
|
CHN_UNLOCK(parent);
|
||||||
|
|
||||||
@ -269,16 +387,7 @@ vchan_create(struct pcm_channel *parent)
|
|||||||
CHN_LOCK(parent);
|
CHN_LOCK(parent);
|
||||||
return ENODEV;
|
return ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHN_LOCK(parent);
|
|
||||||
if (!(parent->flags & CHN_F_BUSY))
|
|
||||||
return EBUSY;
|
|
||||||
|
|
||||||
first = SLIST_EMPTY(&parent->children);
|
|
||||||
/* add us to our parent channel's children */
|
|
||||||
pce->channel = child;
|
pce->channel = child;
|
||||||
SLIST_INSERT_HEAD(&parent->children, pce, link);
|
|
||||||
CHN_UNLOCK(parent);
|
|
||||||
|
|
||||||
/* add us to our grandparent's channel list */
|
/* add us to our grandparent's channel list */
|
||||||
/*
|
/*
|
||||||
@ -288,34 +397,112 @@ vchan_create(struct pcm_channel *parent)
|
|||||||
if (err) {
|
if (err) {
|
||||||
pcm_chn_destroy(child);
|
pcm_chn_destroy(child);
|
||||||
free(pce, M_DEVBUF);
|
free(pce, M_DEVBUF);
|
||||||
|
CHN_LOCK(parent);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
CHN_LOCK(parent);
|
CHN_LOCK(parent);
|
||||||
/* XXX gross ugly hack, murder death kill */
|
/* add us to our parent channel's children */
|
||||||
if (first && !err) {
|
first = SLIST_EMPTY(&parent->children);
|
||||||
err = chn_reset(parent, AFMT_STEREO | AFMT_S16_LE);
|
SLIST_INSERT_HEAD(&parent->children, pce, link);
|
||||||
if (err)
|
parent->flags |= CHN_F_HAS_VCHAN;
|
||||||
printf("chn_reset: %d\n", err);
|
|
||||||
speed = 44100;
|
if (first) {
|
||||||
parent_caps = chn_getcaps(parent);
|
parent_caps = chn_getcaps(parent);
|
||||||
if (parent_caps != NULL) {
|
if (parent_caps == NULL)
|
||||||
|
err = EINVAL;
|
||||||
|
|
||||||
|
if (!err)
|
||||||
|
err = chn_reset(parent, AFMT_STEREO | AFMT_S16_LE);
|
||||||
|
|
||||||
|
if (!err) {
|
||||||
|
fake = pcm_getfakechan(d);
|
||||||
|
if (fake != NULL) {
|
||||||
|
/*
|
||||||
|
* Avoid querying kernel hint, use saved value
|
||||||
|
* from fake channel.
|
||||||
|
*/
|
||||||
|
CHN_UNLOCK(parent);
|
||||||
|
CHN_LOCK(fake);
|
||||||
|
speed = fake->speed;
|
||||||
|
CHN_UNLOCK(fake);
|
||||||
|
CHN_LOCK(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is very sad. Few soundcards advertised as being
|
||||||
|
* able to do (insanely) higher/lower speed, but in
|
||||||
|
* reality, they simply can't. At least, we give user chance
|
||||||
|
* to set sane value via kernel hints or sysctl.
|
||||||
|
*/
|
||||||
|
if (speed < 1) {
|
||||||
|
int r;
|
||||||
|
CHN_UNLOCK(parent);
|
||||||
|
r = resource_int_value(device_get_name(parent->dev),
|
||||||
|
device_get_unit(parent->dev),
|
||||||
|
"vchanrate", &speed);
|
||||||
|
CHN_LOCK(parent);
|
||||||
|
if (r != 0)
|
||||||
|
speed = VCHAN_DEFAULT_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Limit speed based on driver caps.
|
* Limit speed based on driver caps.
|
||||||
* This is supposed to help fixed rate, non-VRA
|
* This is supposed to help fixed rate, non-VRA
|
||||||
* AC97 cards.
|
* AC97 cards, but.. (see below)
|
||||||
*/
|
*/
|
||||||
if (speed < parent_caps->minspeed)
|
if (speed < parent_caps->minspeed)
|
||||||
speed = parent_caps->minspeed;
|
speed = parent_caps->minspeed;
|
||||||
if (speed > parent_caps->maxspeed)
|
if (speed > parent_caps->maxspeed)
|
||||||
speed = parent_caps->maxspeed;
|
speed = parent_caps->maxspeed;
|
||||||
}
|
|
||||||
|
/*
|
||||||
|
* We still need to limit the speed between
|
||||||
|
* feeder_rate_ratemin <-> feeder_rate_ratemax. This is
|
||||||
|
* just an escape goat if all of the above failed
|
||||||
|
* miserably.
|
||||||
|
*/
|
||||||
|
if (speed < feeder_rate_ratemin)
|
||||||
|
speed = feeder_rate_ratemin;
|
||||||
|
if (speed > feeder_rate_ratemax)
|
||||||
|
speed = feeder_rate_ratemax;
|
||||||
|
|
||||||
|
err = chn_setspeed(parent, speed);
|
||||||
|
/*
|
||||||
|
* Try to avoid FEEDER_RATE on parent channel if the
|
||||||
|
* requested value is not supported by the hardware.
|
||||||
|
*/
|
||||||
|
if (!err && (parent->feederflags & (1 << FEEDER_RATE))) {
|
||||||
|
speed = sndbuf_getspd(parent->bufhard);
|
||||||
err = chn_setspeed(parent, speed);
|
err = chn_setspeed(parent, speed);
|
||||||
if (err)
|
|
||||||
printf("chn_setspeed: %d\n", err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!err && fake != NULL) {
|
||||||
|
/*
|
||||||
|
* Save new value to fake channel.
|
||||||
|
*/
|
||||||
|
CHN_UNLOCK(parent);
|
||||||
|
CHN_LOCK(fake);
|
||||||
|
fake->speed = speed;
|
||||||
|
CHN_UNLOCK(fake);
|
||||||
|
CHN_LOCK(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
SLIST_REMOVE(&parent->children, pce, pcmchan_children, link);
|
||||||
|
parent->flags &= ~CHN_F_HAS_VCHAN;
|
||||||
|
CHN_UNLOCK(parent);
|
||||||
|
free(pce, M_DEVBUF);
|
||||||
|
pcm_chn_remove(d, child);
|
||||||
|
pcm_chn_destroy(child);
|
||||||
|
CHN_LOCK(parent);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
vchan_destroy(struct pcm_channel *c)
|
vchan_destroy(struct pcm_channel *c)
|
||||||
@ -361,18 +548,28 @@ vchan_destroy(struct pcm_channel *c)
|
|||||||
free(pce, M_DEVBUF);
|
free(pce, M_DEVBUF);
|
||||||
|
|
||||||
last = SLIST_EMPTY(&parent->children);
|
last = SLIST_EMPTY(&parent->children);
|
||||||
if (last)
|
if (last) {
|
||||||
parent->flags &= ~CHN_F_BUSY;
|
parent->flags &= ~CHN_F_BUSY;
|
||||||
|
parent->flags &= ~CHN_F_HAS_VCHAN;
|
||||||
|
}
|
||||||
|
|
||||||
/* remove us from our grandparent's channel list */
|
/* remove us from our grandparent's channel list */
|
||||||
err = pcm_chn_remove(d, c);
|
err = pcm_chn_remove(d, c);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
CHN_UNLOCK(parent);
|
CHN_UNLOCK(parent);
|
||||||
/* destroy ourselves */
|
/* destroy ourselves */
|
||||||
|
if (!err)
|
||||||
err = pcm_chn_destroy(c);
|
err = pcm_chn_destroy(c);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (!err && last) {
|
||||||
|
CHN_LOCK(parent);
|
||||||
|
chn_reset(parent, chn_getcaps(parent)->fmtlist[0]);
|
||||||
|
chn_setspeed(parent, chn_getcaps(parent)->minspeed);
|
||||||
|
CHN_UNLOCK(parent);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,9 +583,12 @@ vchan_initsys(device_t dev)
|
|||||||
SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
||||||
OID_AUTO, "vchans", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
|
OID_AUTO, "vchans", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
|
||||||
sysctl_hw_snd_vchans, "I", "");
|
sysctl_hw_snd_vchans, "I", "");
|
||||||
|
#if 0
|
||||||
|
SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)),
|
||||||
|
OID_AUTO, "vchanrate", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d),
|
||||||
|
sysctl_hw_snd_vchanrate, "I", "");
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -41,7 +41,7 @@ int uaudio_halt_in_dma(device_t dev);
|
|||||||
#endif
|
#endif
|
||||||
void uaudio_chan_set_param(device_t, u_char *, u_char *);
|
void uaudio_chan_set_param(device_t, u_char *, u_char *);
|
||||||
void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir);
|
void uaudio_chan_set_param_blocksize(device_t dev, u_int32_t blocksize, int dir);
|
||||||
void uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int dir);
|
int uaudio_chan_set_param_speed(device_t dev, u_int32_t speed, int reqdir);
|
||||||
void uaudio_chan_set_param_format(device_t dev, u_int32_t format,int dir);
|
void uaudio_chan_set_param_format(device_t dev, u_int32_t format,int dir);
|
||||||
int uaudio_chan_getptr(device_t dev, int);
|
int uaudio_chan_getptr(device_t dev, int);
|
||||||
void uaudio_mixer_set(device_t dev, unsigned type, unsigned left,
|
void uaudio_mixer_set(device_t dev, unsigned type, unsigned left,
|
||||||
@ -49,5 +49,5 @@ void uaudio_mixer_set(device_t dev, unsigned type, unsigned left,
|
|||||||
u_int32_t uaudio_mixer_setrecsrc(device_t dev, u_int32_t src);
|
u_int32_t uaudio_mixer_setrecsrc(device_t dev, u_int32_t src);
|
||||||
u_int32_t uaudio_query_mix_info(device_t dev);
|
u_int32_t uaudio_query_mix_info(device_t dev);
|
||||||
u_int32_t uaudio_query_recsrc_info(device_t dev);
|
u_int32_t uaudio_query_recsrc_info(device_t dev);
|
||||||
void uaudio_query_formats(device_t dev, u_int32_t *pfmt, u_int32_t *rfmt);
|
unsigned uaudio_query_formats(device_t dev, int dir, unsigned maxfmt, struct pcmchan_caps *fmt);
|
||||||
void uaudio_sndstat_register(device_t dev);
|
void uaudio_sndstat_register(device_t dev);
|
||||||
|
@ -49,16 +49,13 @@ struct ua_info {
|
|||||||
device_t sc_dev;
|
device_t sc_dev;
|
||||||
u_int32_t bufsz;
|
u_int32_t bufsz;
|
||||||
struct ua_chinfo pch, rch;
|
struct ua_chinfo pch, rch;
|
||||||
|
#define FORMAT_NUM 32
|
||||||
|
u_int32_t ua_playfmt[FORMAT_NUM*2+1]; /* FORMAT_NUM format * (stereo or mono) + endptr */
|
||||||
|
u_int32_t ua_recfmt[FORMAT_NUM*2+1]; /* FORMAT_NUM format * (stereo or mono) + endptr */
|
||||||
|
struct pcmchan_caps ua_playcaps;
|
||||||
|
struct pcmchan_caps ua_reccaps;
|
||||||
};
|
};
|
||||||
|
|
||||||
static u_int32_t ua_playfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
|
|
||||||
|
|
||||||
static struct pcmchan_caps ua_playcaps = {8000, 48000, ua_playfmt, 0};
|
|
||||||
|
|
||||||
static u_int32_t ua_recfmt[8*2+1]; /* 8 format * (stereo or mono) + endptr */
|
|
||||||
|
|
||||||
static struct pcmchan_caps ua_reccaps = {8000, 48000, ua_recfmt, 0};
|
|
||||||
|
|
||||||
#define UAUDIO_DEFAULT_BUFSZ 16*1024
|
#define UAUDIO_DEFAULT_BUFSZ 16*1024
|
||||||
|
|
||||||
/************************************************************/
|
/************************************************************/
|
||||||
@ -76,20 +73,6 @@ ua_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b, struct pcm_channel *
|
|||||||
ch->dir = dir;
|
ch->dir = dir;
|
||||||
|
|
||||||
pa_dev = device_get_parent(sc->sc_dev);
|
pa_dev = device_get_parent(sc->sc_dev);
|
||||||
/* Create ua_playfmt[] & ua_recfmt[] */
|
|
||||||
uaudio_query_formats(pa_dev, (u_int32_t *)&ua_playfmt, (u_int32_t *)&ua_recfmt);
|
|
||||||
if (dir == PCMDIR_PLAY) {
|
|
||||||
if (ua_playfmt[0] == 0) {
|
|
||||||
printf("play channel supported format list invalid\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ua_recfmt[0] == 0) {
|
|
||||||
printf("record channel supported format list invalid\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ch->buf = malloc(sc->bufsz, M_DEVBUF, M_NOWAIT);
|
ch->buf = malloc(sc->bufsz, M_DEVBUF, M_NOWAIT);
|
||||||
if (ch->buf == NULL)
|
if (ch->buf == NULL)
|
||||||
@ -133,6 +116,9 @@ ua_chan_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
|
|
||||||
struct ua_chinfo *ch = data;
|
struct ua_chinfo *ch = data;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* At this point, no need to query as we shouldn't select an unsorted format
|
||||||
|
*/
|
||||||
ua = ch->parent;
|
ua = ch->parent;
|
||||||
pa_dev = device_get_parent(ua->sc_dev);
|
pa_dev = device_get_parent(ua->sc_dev);
|
||||||
uaudio_chan_set_param_format(pa_dev, format, ch->dir);
|
uaudio_chan_set_param_format(pa_dev, format, ch->dir);
|
||||||
@ -144,15 +130,15 @@ ua_chan_setformat(kobj_t obj, void *data, u_int32_t format)
|
|||||||
static int
|
static int
|
||||||
ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
ua_chan_setspeed(kobj_t obj, void *data, u_int32_t speed)
|
||||||
{
|
{
|
||||||
|
struct ua_chinfo *ch;
|
||||||
device_t pa_dev;
|
device_t pa_dev;
|
||||||
struct ua_info *ua;
|
int bestspeed;
|
||||||
|
|
||||||
struct ua_chinfo *ch = data;
|
ch = data;
|
||||||
ch->spd = speed;
|
pa_dev = device_get_parent(ch->parent->sc_dev);
|
||||||
|
|
||||||
ua = ch->parent;
|
if ((bestspeed = uaudio_chan_set_param_speed(pa_dev, speed, ch->dir)))
|
||||||
pa_dev = device_get_parent(ua->sc_dev);
|
ch->spd = bestspeed;
|
||||||
uaudio_chan_set_param_speed(pa_dev, speed, ch->dir);
|
|
||||||
|
|
||||||
return ch->spd;
|
return ch->spd;
|
||||||
}
|
}
|
||||||
@ -224,9 +210,10 @@ ua_chan_getptr(kobj_t obj, void *data)
|
|||||||
static struct pcmchan_caps *
|
static struct pcmchan_caps *
|
||||||
ua_chan_getcaps(kobj_t obj, void *data)
|
ua_chan_getcaps(kobj_t obj, void *data)
|
||||||
{
|
{
|
||||||
struct ua_chinfo *ch = data;
|
struct ua_chinfo *ch;
|
||||||
|
|
||||||
return (ch->dir == PCMDIR_PLAY) ? &ua_playcaps : & ua_reccaps;
|
ch = data;
|
||||||
|
return (ch->dir == PCMDIR_PLAY) ? &(ch->parent->ua_playcaps) : &(ch->parent->ua_reccaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
static kobj_method_t ua_chan_methods[] = {
|
static kobj_method_t ua_chan_methods[] = {
|
||||||
@ -249,11 +236,20 @@ ua_mixer_init(struct snd_mixer *m)
|
|||||||
{
|
{
|
||||||
u_int32_t mask;
|
u_int32_t mask;
|
||||||
device_t pa_dev;
|
device_t pa_dev;
|
||||||
|
struct snddev_info *d;
|
||||||
struct ua_info *ua = mix_getdevinfo(m);
|
struct ua_info *ua = mix_getdevinfo(m);
|
||||||
|
|
||||||
pa_dev = device_get_parent(ua->sc_dev);
|
pa_dev = device_get_parent(ua->sc_dev);
|
||||||
|
d = device_get_softc(ua->sc_dev);
|
||||||
|
|
||||||
mask = uaudio_query_mix_info(pa_dev);
|
mask = uaudio_query_mix_info(pa_dev);
|
||||||
|
if (d && !(mask & SOUND_MIXER_PCM)) {
|
||||||
|
/*
|
||||||
|
* Emulate missing pcm mixer controller
|
||||||
|
* through FEEDER_VOLUME
|
||||||
|
*/
|
||||||
|
d->flags |= SD_F_SOFTVOL;
|
||||||
|
}
|
||||||
mix_setdevs(m, mask);
|
mix_setdevs(m, mask);
|
||||||
|
|
||||||
mask = uaudio_query_recsrc_info(pa_dev);
|
mask = uaudio_query_recsrc_info(pa_dev);
|
||||||
@ -318,42 +314,63 @@ ua_attach(device_t dev)
|
|||||||
{
|
{
|
||||||
struct ua_info *ua;
|
struct ua_info *ua;
|
||||||
char status[SND_STATUSLEN];
|
char status[SND_STATUSLEN];
|
||||||
|
device_t pa_dev;
|
||||||
|
u_int32_t nplay, nrec;
|
||||||
|
int i;
|
||||||
|
|
||||||
ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_NOWAIT);
|
ua = (struct ua_info *)malloc(sizeof *ua, M_DEVBUF, M_ZERO | M_NOWAIT);
|
||||||
if (!ua)
|
if (ua == NULL)
|
||||||
return ENXIO;
|
return ENXIO;
|
||||||
bzero(ua, sizeof *ua);
|
|
||||||
|
|
||||||
ua->sc_dev = dev;
|
ua->sc_dev = dev;
|
||||||
|
|
||||||
|
pa_dev = device_get_parent(dev);
|
||||||
|
|
||||||
ua->bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_DEFAULT_BUFSZ, 65536);
|
ua->bufsz = pcm_getbuffersize(dev, 4096, UAUDIO_DEFAULT_BUFSZ, 65536);
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
device_printf(dev, "using a default buffer size of %jd\n", (intmax_t)ua->bufsz);
|
device_printf(dev, "using a default buffer size of %jd\n", (intmax_t)ua->bufsz);
|
||||||
|
|
||||||
if (mixer_init(dev, &ua_mixer_class, ua)) {
|
if (mixer_init(dev, &ua_mixer_class, ua)) {
|
||||||
return(ENXIO);
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(status, SND_STATUSLEN, "at addr ?");
|
snprintf(status, SND_STATUSLEN, "at ? %s", PCM_KLDSTRING(snd_uaudio));
|
||||||
|
|
||||||
|
ua->ua_playcaps.fmtlist = ua->ua_playfmt;
|
||||||
|
ua->ua_reccaps.fmtlist = ua->ua_recfmt;
|
||||||
|
nplay = uaudio_query_formats(pa_dev, PCMDIR_PLAY, FORMAT_NUM * 2, &ua->ua_playcaps);
|
||||||
|
nrec = uaudio_query_formats(pa_dev, PCMDIR_REC, FORMAT_NUM * 2, &ua->ua_reccaps);
|
||||||
|
|
||||||
|
if (nplay > 1)
|
||||||
|
nplay = 1;
|
||||||
|
if (nrec > 1)
|
||||||
|
nrec = 1;
|
||||||
|
|
||||||
#ifndef NO_RECORDING
|
#ifndef NO_RECORDING
|
||||||
if (pcm_register(dev, ua, 1, 1)) {
|
if (pcm_register(dev, ua, nplay, nrec)) {
|
||||||
#else
|
#else
|
||||||
if (pcm_register(dev, ua, 1, 0)) {
|
if (pcm_register(dev, ua, nplay, 0)) {
|
||||||
#endif
|
#endif
|
||||||
return(ENXIO);
|
goto bad;
|
||||||
}
|
}
|
||||||
|
|
||||||
sndstat_unregister(dev);
|
sndstat_unregister(dev);
|
||||||
uaudio_sndstat_register(dev);
|
uaudio_sndstat_register(dev);
|
||||||
|
|
||||||
|
for (i = 0; i < nplay; i++) {
|
||||||
pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
|
pcm_addchan(dev, PCMDIR_PLAY, &ua_chan_class, ua);
|
||||||
|
}
|
||||||
#ifndef NO_RECORDING
|
#ifndef NO_RECORDING
|
||||||
|
for (i = 0; i < nrec; i++) {
|
||||||
pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
|
pcm_addchan(dev, PCMDIR_REC, &ua_chan_class, ua);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
pcm_setstatus(dev, status);
|
pcm_setstatus(dev, status);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
bad: free(ua, M_DEVBUF);
|
||||||
|
return ENXIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# $FreeBSD$
|
# $FreeBSD$
|
||||||
|
|
||||||
.if ${MACHINE_ARCH} == "sparc64"
|
.if ${MACHINE_ARCH} == "sparc64"
|
||||||
SUBDIR = audiocs
|
SUBDIR = audiocs es137x
|
||||||
.else
|
.else
|
||||||
SUBDIR = als4000 ad1816 cmi cs4281 csa ds1 emu10k1 es137x ess
|
SUBDIR = als4000 ad1816 atiixp cmi cs4281 csa ds1 emu10k1 es137x ess
|
||||||
SUBDIR += fm801 ich maestro maestro3 mss neomagic sb16 sb8 sbc solo
|
SUBDIR += fm801 ich maestro maestro3 mss neomagic sb16 sb8 sbc solo
|
||||||
SUBDIR += t4dwave via8233 via82c686 vibes
|
SUBDIR += t4dwave via8233 via82c686 vibes
|
||||||
SUBDIR += driver uaudio
|
SUBDIR += driver uaudio
|
||||||
|
@ -8,7 +8,7 @@ SRCS= device_if.h bus_if.h isa_if.h pci_if.h opt_isa.h
|
|||||||
SRCS+= ac97_if.h channel_if.h feeder_if.h mixer_if.h
|
SRCS+= ac97_if.h channel_if.h feeder_if.h mixer_if.h
|
||||||
SRCS+= ac97_if.c channel_if.c feeder_if.c mixer_if.c
|
SRCS+= ac97_if.c channel_if.c feeder_if.c mixer_if.c
|
||||||
SRCS+= ac97.c ac97_patch.c buffer.c channel.c dsp.c
|
SRCS+= ac97.c ac97_patch.c buffer.c channel.c dsp.c
|
||||||
SRCS+= fake.c feeder.c feeder_fmt.c feeder_rate.c
|
SRCS+= fake.c feeder.c feeder_fmt.c feeder_rate.c feeder_volume.c
|
||||||
SRCS+= mixer.c sndstat.c sound.c vchan.c
|
SRCS+= mixer.c sndstat.c sound.c vchan.c
|
||||||
|
|
||||||
EXPORT_SYMS= YES # XXX evaluate
|
EXPORT_SYMS= YES # XXX evaluate
|
||||||
|
@ -180,6 +180,10 @@ struct snd_size {
|
|||||||
#define AFMT_S32_BE 0x00002000 /* Big endian signed 32-bit */
|
#define AFMT_S32_BE 0x00002000 /* Big endian signed 32-bit */
|
||||||
#define AFMT_U32_LE 0x00004000 /* Little endian unsigned 32-bit */
|
#define AFMT_U32_LE 0x00004000 /* Little endian unsigned 32-bit */
|
||||||
#define AFMT_U32_BE 0x00008000 /* Big endian unsigned 32-bit */
|
#define AFMT_U32_BE 0x00008000 /* Big endian unsigned 32-bit */
|
||||||
|
#define AFMT_S24_LE 0x00010000 /* Little endian signed 24-bit */
|
||||||
|
#define AFMT_S24_BE 0x00020000 /* Big endian signed 24-bit */
|
||||||
|
#define AFMT_U24_LE 0x00040000 /* Little endian unsigned 24-bit */
|
||||||
|
#define AFMT_U24_BE 0x00080000 /* Big endian unsigned 24-bit */
|
||||||
|
|
||||||
#define AFMT_STEREO 0x10000000 /* can do/want stereo */
|
#define AFMT_STEREO 0x10000000 /* can do/want stereo */
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user