git: 516a9c0212b0 - main - sound: Make device registration more intuitive

From: Christos Margiolis <christos_at_FreeBSD.org>
Date: Sun, 03 Nov 2024 19:04:11 UTC
The branch main has been updated by christos:

URL: https://cgit.FreeBSD.org/src/commit/?id=516a9c0212b003e1da0c6f4476dbe4f3f431606c

commit 516a9c0212b003e1da0c6f4476dbe4f3f431606c
Author:     Christos Margiolis <christos@FreeBSD.org>
AuthorDate: 2024-11-03 19:02:49 +0000
Commit:     Christos Margiolis <christos@FreeBSD.org>
CommitDate: 2024-11-03 19:02:49 +0000

    sound: Make device registration more intuitive
    
    The way a sound driver currently registers to sound(4) is using the
    following sequence of function calls:
    
    1. pcm_register() to initialize snddev_info.
    2. pcm_addchan() calls to create the device's primary channels.
    3. pcm_setstatus() to do the final setup.
    
    While using 3 different functions in a specific order might not be very
    elegant, this pattern cannot be easily avoided. However, pcm_register()
    and pcm_setstatus() are especially confusing, since one would
    intuitively expect:
    
    1. pcm_register() to actually do the registration, as opposed to a basic
       initialization.
    2. pcm_setstatus() to, as the name suggests, set some kind of status, as
       opposed to finalizing the registration.
    
    This patch renames pcm_register() to pcm_init(), and pcm_setstatus() to
    pcm_register(). Drivers are modified accordingly.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Reviewed by:    dev_submerge.ch
    Differential Revision:  https://reviews.freebsd.org/D47325
---
 sys/arm/allwinner/a10_codec.c            |  10 +--
 sys/arm/broadcom/bcm2835/bcm2835_audio.c |  10 +--
 sys/arm/freescale/imx/imx6_ssi.c         |  12 ++--
 sys/arm/freescale/vybrid/vf_sai.c        |  12 ++--
 sys/dev/sound/dummy.c                    |   6 +-
 sys/dev/sound/fdt/audio_soc.c            |  10 +--
 sys/dev/sound/macio/aoa.c                |   6 +-
 sys/dev/sound/pci/als4000.c              |  11 ++--
 sys/dev/sound/pci/atiixp.c               |   6 +-
 sys/dev/sound/pci/cmi.c                  |   6 +-
 sys/dev/sound/pci/cs4281.c               |   6 +-
 sys/dev/sound/pci/csapcm.c               |   8 +--
 sys/dev/sound/pci/emu10k1.c              |   5 +-
 sys/dev/sound/pci/emu10kx-pcm.c          |   8 +--
 sys/dev/sound/pci/envy24.c               |   7 +--
 sys/dev/sound/pci/envy24ht.c             |   8 +--
 sys/dev/sound/pci/es137x.c               |   6 +-
 sys/dev/sound/pci/fm801.c                |   5 +-
 sys/dev/sound/pci/hda/hdaa.c             |   7 +--
 sys/dev/sound/pci/hdsp-pcm.c             |  13 ++--
 sys/dev/sound/pci/hdspe-pcm.c            |  13 ++--
 sys/dev/sound/pci/ich.c                  |   5 +-
 sys/dev/sound/pci/maestro3.c             |   9 +--
 sys/dev/sound/pci/neomagic.c             |   5 +-
 sys/dev/sound/pci/solo.c                 |   6 +-
 sys/dev/sound/pci/t4dwave.c              |   6 +-
 sys/dev/sound/pci/via8233.c              |   6 +-
 sys/dev/sound/pci/via82c686.c            |   5 +-
 sys/dev/sound/pci/vibes.c                |  11 ++--
 sys/dev/sound/pcm/sound.c                | 103 ++++++++++++++++---------------
 sys/dev/sound/pcm/sound.h                |   4 +-
 sys/dev/sound/usb/uaudio.c               |  11 ++--
 32 files changed, 168 insertions(+), 178 deletions(-)

diff --git a/sys/arm/allwinner/a10_codec.c b/sys/arm/allwinner/a10_codec.c
index 9294c1e5290c..12d389d24243 100644
--- a/sys/arm/allwinner/a10_codec.c
+++ b/sys/arm/allwinner/a10_codec.c
@@ -1165,16 +1165,16 @@ a10codec_attach(device_t dev)
 
 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
 
-	if (pcm_register(dev, sc, 1, 1)) {
-		device_printf(dev, "pcm_register failed\n");
-		goto fail;
-	}
+	pcm_init(dev, sc);
 
 	pcm_addchan(dev, PCMDIR_PLAY, &a10codec_chan_class, sc);
 	pcm_addchan(dev, PCMDIR_REC, &a10codec_chan_class, sc);
 
 	snprintf(status, SND_STATUSLEN, "at %s", ofw_bus_get_name(dev));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status)) {
+		device_printf(dev, "pcm_register failed\n");
+		goto fail;
+	}
 
 	return (0);
 
diff --git a/sys/arm/broadcom/bcm2835/bcm2835_audio.c b/sys/arm/broadcom/bcm2835/bcm2835_audio.c
index 75a0c81f29a1..13f309dd3f11 100644
--- a/sys/arm/broadcom/bcm2835/bcm2835_audio.c
+++ b/sys/arm/broadcom/bcm2835/bcm2835_audio.c
@@ -867,14 +867,14 @@ bcm2835_audio_delayed_init(void *xsc)
 		goto no;
 	}
 
-    	if (pcm_register(sc->dev, sc, 1, 0)) {
-		device_printf(sc->dev, "pcm_register failed\n");
-		goto no;
-	}
+	pcm_init(sc->dev, sc);
 
 	pcm_addchan(sc->dev, PCMDIR_PLAY, &bcmchan_class, sc);
     	snprintf(status, SND_STATUSLEN, "at VCHIQ");
-	pcm_setstatus(sc->dev, status);
+	if (pcm_register(sc->dev, status)) {
+		device_printf(sc->dev, "pcm_register failed\n");
+		goto no;
+	}
 
 	bcm2835_audio_reset_channel(&sc->pch);
 	bcm2835_audio_create_worker(sc);
diff --git a/sys/arm/freescale/imx/imx6_ssi.c b/sys/arm/freescale/imx/imx6_ssi.c
index 273957f64b21..cb77f1454e63 100644
--- a/sys/arm/freescale/imx/imx6_ssi.c
+++ b/sys/arm/freescale/imx/imx6_ssi.c
@@ -810,18 +810,18 @@ ssi_attach(device_t dev)
 
 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
 
-	err = pcm_register(dev, scp, 1, 0);
-	if (err) {
-		device_printf(dev, "Can't register pcm.\n");
-		return (ENXIO);
-	}
+	pcm_init(dev, scp);
 
 	scp->chnum = 0;
 	pcm_addchan(dev, PCMDIR_PLAY, &ssichan_class, scp);
 	scp->chnum++;
 
 	snprintf(status, SND_STATUSLEN, "at simplebus");
-	pcm_setstatus(dev, status);
+	err = pcm_register(dev, status);
+	if (err) {
+		device_printf(dev, "Can't register pcm.\n");
+		return (ENXIO);
+	}
 
 	mixer_init(dev, &ssimixer_class, scp);
 	setup_ssi(sc);
diff --git a/sys/arm/freescale/vybrid/vf_sai.c b/sys/arm/freescale/vybrid/vf_sai.c
index 696ecfb980f4..e895529c4810 100644
--- a/sys/arm/freescale/vybrid/vf_sai.c
+++ b/sys/arm/freescale/vybrid/vf_sai.c
@@ -762,18 +762,18 @@ sai_attach(device_t dev)
 
 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
 
-	err = pcm_register(dev, scp, 1, 0);
-	if (err) {
-		device_printf(dev, "Can't register pcm.\n");
-		return (ENXIO);
-	}
+	pcm_init(dev, scp);
 
 	scp->chnum = 0;
 	pcm_addchan(dev, PCMDIR_PLAY, &saichan_class, scp);
 	scp->chnum++;
 
 	snprintf(status, SND_STATUSLEN, "at simplebus");
-	pcm_setstatus(dev, status);
+	err = pcm_register(dev, status);
+	if (err) {
+		device_printf(dev, "Can't register pcm.\n");
+		return (ENXIO);
+	}
 
 	mixer_init(dev, &saimixer_class, scp);
 
diff --git a/sys/dev/sound/dummy.c b/sys/dev/sound/dummy.c
index c1cd4dff15f9..9013fd023a7e 100644
--- a/sys/dev/sound/dummy.c
+++ b/sys/dev/sound/dummy.c
@@ -305,8 +305,7 @@ dummy_attach(device_t dev)
 	};
 
 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
-	if (pcm_register(dev, sc, DUMMY_NPCHAN, DUMMY_NRCHAN))
-		return (ENXIO);
+	pcm_init(dev, sc);
 	for (i = 0; i < DUMMY_NPCHAN; i++)
 		pcm_addchan(dev, PCMDIR_PLAY, &dummy_chan_class, sc);
 	for (i = 0; i < DUMMY_NRCHAN; i++)
@@ -314,7 +313,8 @@ dummy_attach(device_t dev)
 
 	snprintf(status, SND_STATUSLEN, "on %s",
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		return (ENXIO);
 	mixer_init(dev, &dummy_mixer_class, sc);
 	callout_init(&sc->callout, 1);
 
diff --git a/sys/dev/sound/fdt/audio_soc.c b/sys/dev/sound/fdt/audio_soc.c
index 92813a3079d8..c2bdea399364 100644
--- a/sys/dev/sound/fdt/audio_soc.c
+++ b/sys/dev/sound/fdt/audio_soc.c
@@ -397,10 +397,7 @@ audio_soc_init(void *arg)
 		}
 	}
 
-	if (pcm_register(sc->dev, sc, 1, 1)) {
-		device_printf(sc->dev, "failed to register PCM\n");
-		return;
-	}
+	pcm_init(sc->dev, sc);
 
 	sc->play_channel.sc = sc;
 	sc->rec_channel.sc = sc;
@@ -408,7 +405,10 @@ audio_soc_init(void *arg)
 	pcm_addchan(sc->dev, PCMDIR_PLAY, &audio_soc_chan_class, &sc->play_channel);
 	pcm_addchan(sc->dev, PCMDIR_REC, &audio_soc_chan_class, &sc->rec_channel);
 
-	pcm_setstatus(sc->dev, "at simplebus");
+	if (pcm_register(sc->dev, "at simplebus")) {
+		device_printf(sc->dev, "failed to register PCM\n");
+		return;
+	}
 
 	AUDIO_DAI_SETUP_INTR(sc->cpu_dev, audio_soc_intr, sc);
 	AUDIO_DAI_SETUP_MIXER(sc->codec_dev, sc->dev);
diff --git a/sys/dev/sound/macio/aoa.c b/sys/dev/sound/macio/aoa.c
index 27626b3d570a..9861bbd92a0c 100644
--- a/sys/dev/sound/macio/aoa.c
+++ b/sys/dev/sound/macio/aoa.c
@@ -372,8 +372,7 @@ aoa_attach(void *xsc)
 	sc = xsc;
 	self = sc->sc_dev;
 
-	if (pcm_register(self, sc, 1, 0))
-		return (ENXIO);
+	pcm_init(self, sc);
 
 	err = pcm_getbuffersize(self, AOA_BUFFER_SIZE, AOA_BUFFER_SIZE,
 	    AOA_BUFFER_SIZE);
@@ -382,7 +381,6 @@ aoa_attach(void *xsc)
 	pcm_addchan(self, PCMDIR_PLAY, &aoa_chan_class, sc);
 
 	snprintf(status, sizeof(status), "at %s", ofw_bus_get_name(self)); 
-	pcm_setstatus(self, status);
 
-	return (0);
+	return (pcm_register(self, status));
 }
diff --git a/sys/dev/sound/pci/als4000.c b/sys/dev/sound/pci/als4000.c
index b1376d2b6e5a..9d86713b379e 100644
--- a/sys/dev/sound/pci/als4000.c
+++ b/sys/dev/sound/pci/als4000.c
@@ -839,10 +839,7 @@ als_pci_attach(device_t dev)
 		goto bad_attach;
 	}
 
-	if (pcm_register(dev, sc, 1, 1)) {
-		device_printf(dev, "failed to register pcm entries\n");
-		goto bad_attach;
-	}
+	pcm_init(dev, sc);
 
 	pcm_addchan(dev, PCMDIR_PLAY, &alspchan_class, sc);
 	pcm_addchan(dev, PCMDIR_REC,  &alsrchan_class, sc);
@@ -850,7 +847,11 @@ als_pci_attach(device_t dev)
 	snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s",
 		 rman_get_start(sc->reg), rman_get_start(sc->irq),
 		 device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status)) {
+		device_printf(dev, "failed to register pcm entries\n");
+		goto bad_attach;
+	}
+
 	return 0;
 
  bad_attach:
diff --git a/sys/dev/sound/pci/atiixp.c b/sys/dev/sound/pci/atiixp.c
index eeb28bb08276..90e5742e6523 100644
--- a/sys/dev/sound/pci/atiixp.c
+++ b/sys/dev/sound/pci/atiixp.c
@@ -1084,8 +1084,7 @@ atiixp_chip_post_init(void *arg)
 
 	mixer_init(sc->dev, ac97_getmixerclass(), sc->codec);
 
-	if (pcm_register(sc->dev, sc, ATI_IXP_NPCHAN, ATI_IXP_NRCHAN))
-		goto postinitbad;
+	pcm_init(sc->dev, sc);
 
 	for (i = 0; i < ATI_IXP_NPCHAN; i++)
 		pcm_addchan(sc->dev, PCMDIR_PLAY, &atiixp_chan_class, sc);
@@ -1101,7 +1100,8 @@ atiixp_chip_post_init(void *arg)
 	    rman_get_start(sc->reg), rman_get_start(sc->irq),
 	    device_get_nameunit(device_get_parent(sc->dev)));
 
-	pcm_setstatus(sc->dev, status);
+	if (pcm_register(sc->dev, status))
+		goto postinitbad;
 
 	atiixp_lock(sc);
 	if (sc->polling == 0)
diff --git a/sys/dev/sound/pci/cmi.c b/sys/dev/sound/pci/cmi.c
index 9a92066c51a4..22f1e76a4d1f 100644
--- a/sys/dev/sound/pci/cmi.c
+++ b/sys/dev/sound/pci/cmi.c
@@ -982,8 +982,7 @@ cmi_attach(device_t dev)
 	if (mixer_init(dev, &cmi_mixer_class, sc))
 		goto bad;
 
-	if (pcm_register(dev, sc, 1, 1))
-		goto bad;
+	pcm_init(dev, sc);
 
 	cmi_initsys(sc);
 
@@ -993,7 +992,8 @@ cmi_attach(device_t dev)
 	snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s",
 		 rman_get_start(sc->reg), rman_get_start(sc->irq),
 		 device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	DEB(printf("cmi_attach: succeeded\n"));
 	return 0;
diff --git a/sys/dev/sound/pci/cs4281.c b/sys/dev/sound/pci/cs4281.c
index 972b83efff8f..7a25f7f4c08d 100644
--- a/sys/dev/sound/pci/cs4281.c
+++ b/sys/dev/sound/pci/cs4281.c
@@ -839,8 +839,7 @@ cs4281_pci_attach(device_t dev)
 
     mixer_init(dev, ac97_getmixerclass(), codec);
 
-    if (pcm_register(dev, sc, 1, 1))
-	goto bad;
+    pcm_init(dev, sc);
 
     pcm_addchan(dev, PCMDIR_PLAY, &cs4281chan_class, sc);
     pcm_addchan(dev, PCMDIR_REC, &cs4281chan_class, sc);
@@ -849,7 +848,8 @@ cs4281_pci_attach(device_t dev)
 	     (sc->regtype == SYS_RES_IOPORT)? "port" : "mem",
 	     rman_get_start(sc->reg), rman_get_start(sc->irq),
 	     device_get_nameunit(device_get_parent(dev)));
-    pcm_setstatus(dev, status);
+    if (pcm_register(dev, status))
+	goto bad;
 
     return 0;
 
diff --git a/sys/dev/sound/pci/csapcm.c b/sys/dev/sound/pci/csapcm.c
index c8424dd3e433..a966a2e66402 100644
--- a/sys/dev/sound/pci/csapcm.c
+++ b/sys/dev/sound/pci/csapcm.c
@@ -832,14 +832,14 @@ pcmcsa_attach(device_t dev)
 	csa_writemem(resp, BA1_CIE, (csa_readmem(resp, BA1_CIE) & ~0x0000003f) | 0x00000001);
 	csa_active(csa, -1);
 
-	if (pcm_register(dev, csa, 1, 1)) {
+	pcm_init(dev, csa);
+	pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa);
+	pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa);
+	if (pcm_register(dev, status)) {
 		ac97_destroy(codec);
 		csa_releaseres(csa, dev);
 		return (ENXIO);
 	}
-	pcm_addchan(dev, PCMDIR_REC, &csachan_class, csa);
-	pcm_addchan(dev, PCMDIR_PLAY, &csachan_class, csa);
-	pcm_setstatus(dev, status);
 
 	return (0);
 }
diff --git a/sys/dev/sound/pci/emu10k1.c b/sys/dev/sound/pci/emu10k1.c
index 0813f89c87b8..e4b2c22f4f07 100644
--- a/sys/dev/sound/pci/emu10k1.c
+++ b/sys/dev/sound/pci/emu10k1.c
@@ -2130,13 +2130,14 @@ emu_pci_attach(device_t dev)
 	    rman_get_start(sc->reg), rman_get_start(sc->irq),
 	    device_get_nameunit(device_get_parent(dev)));
 
-	if (pcm_register(dev, sc, sc->nchans, gotmic ? 3 : 2)) goto bad;
+	pcm_init(dev, sc);
 	for (i = 0; i < sc->nchans; i++)
 		pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc);
 	for (i = 0; i < (gotmic ? 3 : 2); i++)
 		pcm_addchan(dev, PCMDIR_REC, &emurchan_class, sc);
 
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	return 0;
 
diff --git a/sys/dev/sound/pci/emu10kx-pcm.c b/sys/dev/sound/pci/emu10kx-pcm.c
index bef6b596646e..c280b64892f6 100644
--- a/sys/dev/sound/pci/emu10kx-pcm.c
+++ b/sys/dev/sound/pci/emu10kx-pcm.c
@@ -1459,10 +1459,7 @@ emu_pcm_attach(device_t dev)
 	pcm_setflags(dev, pcm_getflags(dev) | SD_F_MPSAFE);
 
 	/* XXX we should better get number of available channels from parent */
-	if (pcm_register(dev, sc, (route == RT_FRONT) ? MAX_CHANNELS : 1, (route == RT_FRONT) ? 1 : 0)) {
-		device_printf(dev, "can't register PCM channels!\n");
-		goto bad;
-	}
+	pcm_init(dev, sc);
 	sc->pnum = 0;
 	if (route != RT_MCHRECORD)
 		pcm_addchan(dev, PCMDIR_PLAY, &emupchan_class, sc);
@@ -1476,7 +1473,8 @@ emu_pcm_attach(device_t dev)
 
 	snprintf(status, SND_STATUSLEN, "on %s",
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	return (0);
 
diff --git a/sys/dev/sound/pci/envy24.c b/sys/dev/sound/pci/envy24.c
index f7cc7ff5724d..51842bfdb480 100644
--- a/sys/dev/sound/pci/envy24.c
+++ b/sys/dev/sound/pci/envy24.c
@@ -2575,9 +2575,7 @@ envy24_pci_attach(device_t dev)
 	mixer_init(dev, &envy24mixer_class, sc);
 
 	/* set channel information */
-	err = pcm_register(dev, sc, 5, 2 + sc->adcn);
-	if (err)
-		goto bad;
+	pcm_init(dev, sc);
 	sc->chnum = 0;
 	for (i = 0; i < 5; i++) {
 		pcm_addchan(dev, PCMDIR_PLAY, &envy24chan_class, sc);
@@ -2601,7 +2599,8 @@ envy24_pci_attach(device_t dev)
 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
 	    rman_get_start(sc->irq),
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	return 0;
 
diff --git a/sys/dev/sound/pci/envy24ht.c b/sys/dev/sound/pci/envy24ht.c
index 65c67b84ce53..b8202a9fa7cd 100644
--- a/sys/dev/sound/pci/envy24ht.c
+++ b/sys/dev/sound/pci/envy24ht.c
@@ -2480,10 +2480,7 @@ envy24ht_pci_attach(device_t dev)
 	mixer_init(dev, &envy24htmixer_class, sc);
 
 	/* set channel information */
-	/* err = pcm_register(dev, sc, 5, 2 + sc->adcn); */
-	err = pcm_register(dev, sc, 1, 2 + sc->adcn);
-	if (err)
-		goto bad;
+	pcm_init(dev, sc);
 	sc->chnum = 0;
 	/* for (i = 0; i < 5; i++) { */
 		pcm_addchan(dev, PCMDIR_PLAY, &envy24htchan_class, sc);
@@ -2503,7 +2500,8 @@ envy24ht_pci_attach(device_t dev)
 	    rman_get_end(sc->mt) - rman_get_start(sc->mt) + 1,
 	    rman_get_start(sc->irq),
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	return 0;
 
diff --git a/sys/dev/sound/pci/es137x.c b/sys/dev/sound/pci/es137x.c
index 8f832d899dd3..3c1bea09b5d1 100644
--- a/sys/dev/sound/pci/es137x.c
+++ b/sys/dev/sound/pci/es137x.c
@@ -1861,13 +1861,13 @@ es_pci_attach(device_t dev)
 	    rman_get_start(es->reg), rman_get_start(es->irq),
 	    device_get_nameunit(device_get_parent(dev)));
 
-	if (pcm_register(dev, es, numplay, 1))
-		goto bad;
+	pcm_init(dev, es);
 	for (i = 0; i < numplay; i++)
 		pcm_addchan(dev, PCMDIR_PLAY, ct, es);
 	pcm_addchan(dev, PCMDIR_REC, ct, es);
 	es_init_sysctls(dev);
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 	es->escfg = ES_SET_GP(es->escfg, 0);
 	if (numplay == 1)
 		device_printf(dev, "<Playback: DAC%d / Record: ADC>\n",
diff --git a/sys/dev/sound/pci/fm801.c b/sys/dev/sound/pci/fm801.c
index ab36ff8f453c..ea043e87a59c 100644
--- a/sys/dev/sound/pci/fm801.c
+++ b/sys/dev/sound/pci/fm801.c
@@ -642,10 +642,11 @@ fm801_pci_attach(device_t dev)
 		device_get_nameunit(device_get_parent(dev)));
 
 #define FM801_MAXPLAYCH	1
-	if (pcm_register(dev, fm801, FM801_MAXPLAYCH, 1)) goto oops;
+	pcm_init(dev, fm801);
 	pcm_addchan(dev, PCMDIR_PLAY, &fm801ch_class, fm801);
 	pcm_addchan(dev, PCMDIR_REC, &fm801ch_class, fm801);
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto oops;
 
 	fm801->radio = device_add_child(dev, "radio", DEVICE_UNIT_ANY);
 	bus_generic_attach(dev);
diff --git a/sys/dev/sound/pci/hda/hdaa.c b/sys/dev/sound/pci/hda/hdaa.c
index bf38e6a97483..ee8464a550df 100644
--- a/sys/dev/sound/pci/hda/hdaa.c
+++ b/sys/dev/sound/pci/hda/hdaa.c
@@ -7053,9 +7053,7 @@ hdaa_pcm_attach(device_t dev)
 	HDA_BOOTHVERBOSE(
 		device_printf(dev, "Registering PCM channels...\n");
 	);
-	if (pcm_register(dev, pdevinfo, (pdevinfo->playas >= 0)?1:0,
-	    (pdevinfo->recas >= 0)?1:0) != 0)
-		device_printf(dev, "Can't register PCM\n");
+	pcm_init(dev, pdevinfo);
 
 	pdevinfo->registered++;
 
@@ -7108,9 +7106,8 @@ hdaa_pcm_attach(device_t dev)
 
 	snprintf(status, SND_STATUSLEN, "on %s",
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
 
-	return (0);
+	return (pcm_register(dev, status));
 }
 
 static int
diff --git a/sys/dev/sound/pci/hdsp-pcm.c b/sys/dev/sound/pci/hdsp-pcm.c
index a50fc2b52fc0..5ac571e64fde 100644
--- a/sys/dev/sound/pci/hdsp-pcm.c
+++ b/sys/dev/sound/pci/hdsp-pcm.c
@@ -1073,13 +1073,10 @@ hdsp_pcm_attach(device_t dev)
 		pcm_flags |= SD_F_BITPERFECT;
 	pcm_setflags(dev, pcm_flags);
 
+	pcm_init(dev, scp);
+
 	play = (hdsp_channel_play_ports(scp->hc)) ? 1 : 0;
 	rec = (hdsp_channel_rec_ports(scp->hc)) ? 1 : 0;
-	err = pcm_register(dev, scp, play, rec);
-	if (err) {
-		device_printf(dev, "Can't register pcm.\n");
-		return (ENXIO);
-	}
 
 	scp->chnum = 0;
 	if (play) {
@@ -1096,7 +1093,11 @@ hdsp_pcm_attach(device_t dev)
 	    rman_get_start(scp->sc->cs),
 	    rman_get_start(scp->sc->irq),
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	err = pcm_register(dev, status);
+	if (err) {
+		device_printf(dev, "Can't register pcm.\n");
+		return (ENXIO);
+	}
 
 	mixer_init(dev, &hdspmixer_class, scp);
 
diff --git a/sys/dev/sound/pci/hdspe-pcm.c b/sys/dev/sound/pci/hdspe-pcm.c
index 1f8fbbcef078..09bbbe22dacf 100644
--- a/sys/dev/sound/pci/hdspe-pcm.c
+++ b/sys/dev/sound/pci/hdspe-pcm.c
@@ -1064,13 +1064,10 @@ hdspe_pcm_attach(device_t dev)
 		pcm_flags |= SD_F_BITPERFECT;
 	pcm_setflags(dev, pcm_flags);
 
+	pcm_init(dev, scp);
+
 	play = (hdspe_channel_play_ports(scp->hc)) ? 1 : 0;
 	rec = (hdspe_channel_rec_ports(scp->hc)) ? 1 : 0;
-	err = pcm_register(dev, scp, play, rec);
-	if (err) {
-		device_printf(dev, "Can't register pcm.\n");
-		return (ENXIO);
-	}
 
 	scp->chnum = 0;
 	if (play) {
@@ -1087,7 +1084,11 @@ hdspe_pcm_attach(device_t dev)
 	    rman_get_start(scp->sc->cs),
 	    rman_get_start(scp->sc->irq),
 	    device_get_nameunit(device_get_parent(dev)));
-	pcm_setstatus(dev, status);
+	err = pcm_register(dev, status);
+	if (err) {
+		device_printf(dev, "Can't register pcm.\n");
+		return (ENXIO);
+	}
 
 	mixer_init(dev, &hdspemixer_class, scp);
 
diff --git a/sys/dev/sound/pci/ich.c b/sys/dev/sound/pci/ich.c
index 910a371c6653..500d6d95daac 100644
--- a/sys/dev/sound/pci/ich.c
+++ b/sys/dev/sound/pci/ich.c
@@ -695,7 +695,7 @@ ich_setstatus(struct sc_info *sc)
 		device_printf(sc->dev,
 		    "PCI Master abort workaround enabled\n");
 
-	pcm_setstatus(sc->dev, status);
+	pcm_register(sc->dev, status);
 }
 
 /* -------------------------------------------------------------------- */
@@ -1066,8 +1066,7 @@ ich_pci_attach(device_t dev)
 	    ich_setmap, sc, 0))
 		goto bad;
 
-	if (pcm_register(dev, sc, 1, (sc->hasmic) ? 2 : 1))
-		goto bad;
+	pcm_init(dev, sc);
 
 	pcm_addchan(dev, PCMDIR_PLAY, &ichchan_class, sc);		/* play */
 	pcm_addchan(dev, PCMDIR_REC, &ichchan_class, sc);		/* record */
diff --git a/sys/dev/sound/pci/maestro3.c b/sys/dev/sound/pci/maestro3.c
index f922aa5cec3f..2d102fcd6dbe 100644
--- a/sys/dev/sound/pci/maestro3.c
+++ b/sys/dev/sound/pci/maestro3.c
@@ -1423,10 +1423,7 @@ m3_pci_attach(device_t dev)
 
 	m3_enable_ints(sc);
 
-	if (pcm_register(dev, sc, dacn, adcn)) {
-		device_printf(dev, "pcm_register error\n");
-		goto bad;
-	}
+	pcm_init(dev, sc);
 	for (i=0 ; i<dacn ; i++) {
 		if (pcm_addchan(dev, PCMDIR_PLAY, &m3_pch_class, sc)) {
 			device_printf(dev, "pcm_addchan (play) error\n");
@@ -1443,8 +1440,8 @@ m3_pci_attach(device_t dev)
 	    (sc->regtype == SYS_RES_IOPORT)? "port" : "mem",
 	    rman_get_start(sc->reg), rman_get_start(sc->irq),
 	    device_get_nameunit(device_get_parent(dev)));
-	if (pcm_setstatus(dev, status)) {
-		device_printf(dev, "attach: pcm_setstatus error\n");
+	if (pcm_register(dev, status)) {
+		device_printf(dev, "pcm_register error\n");
 		goto bad;
 	}
 
diff --git a/sys/dev/sound/pci/neomagic.c b/sys/dev/sound/pci/neomagic.c
index 25273633ff18..d7824c990a52 100644
--- a/sys/dev/sound/pci/neomagic.c
+++ b/sys/dev/sound/pci/neomagic.c
@@ -707,10 +707,11 @@ nm_pci_attach(device_t dev)
 		 rman_get_start(sc->irq),
 		 device_get_nameunit(device_get_parent(dev)));
 
-	if (pcm_register(dev, sc, 1, 1)) goto bad;
+	pcm_init(dev, sc);
 	pcm_addchan(dev, PCMDIR_REC, &nmchan_class, sc);
 	pcm_addchan(dev, PCMDIR_PLAY, &nmchan_class, sc);
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	return 0;
 
diff --git a/sys/dev/sound/pci/solo.c b/sys/dev/sound/pci/solo.c
index 82eabf3a4884..90dd2e26ad41 100644
--- a/sys/dev/sound/pci/solo.c
+++ b/sys/dev/sound/pci/solo.c
@@ -1026,11 +1026,11 @@ ess_attach(device_t dev)
 		rman_get_start(sc->irq),
 		device_get_nameunit(device_get_parent(dev)));
 
-    	if (pcm_register(dev, sc, 1, 1))
-		goto no;
+	pcm_init(dev, sc);
       	pcm_addchan(dev, PCMDIR_REC, &esschan_class, sc);
 	pcm_addchan(dev, PCMDIR_PLAY, &esschan_class, sc);
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto no;
 
     	return 0;
 
diff --git a/sys/dev/sound/pci/t4dwave.c b/sys/dev/sound/pci/t4dwave.c
index 653e610febbe..07b9e1004573 100644
--- a/sys/dev/sound/pci/t4dwave.c
+++ b/sys/dev/sound/pci/t4dwave.c
@@ -921,12 +921,12 @@ tr_pci_attach(device_t dev)
 		 rman_get_start(tr->reg), rman_get_start(tr->irq),
 		 device_get_nameunit(device_get_parent(dev)));
 
-	if (pcm_register(dev, tr, dacn, 1))
-		goto bad;
+	pcm_init(dev, tr);
 	pcm_addchan(dev, PCMDIR_REC, &trrchan_class, tr);
 	for (i = 0; i < dacn; i++)
 		pcm_addchan(dev, PCMDIR_PLAY, &trpchan_class, tr);
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 
 	return 0;
 
diff --git a/sys/dev/sound/pci/via8233.c b/sys/dev/sound/pci/via8233.c
index 9f3b312e4365..243353805b94 100644
--- a/sys/dev/sound/pci/via8233.c
+++ b/sys/dev/sound/pci/via8233.c
@@ -1352,8 +1352,7 @@ via_attach(device_t dev)
 	    device_get_nameunit(device_get_parent(dev)));
 
 	/* Register */
-	if (pcm_register(dev, via, via_dxs_chnum + via_sgd_chnum, NWRCHANS))
-	      goto bad;
+	pcm_init(dev, via);
 	for (i = 0; i < via_dxs_chnum; i++)
 	      pcm_addchan(dev, PCMDIR_PLAY, &via8233dxs_class, via);
 	for (i = 0; i < via_sgd_chnum; i++)
@@ -1366,7 +1365,8 @@ via_attach(device_t dev)
 	    (via_dxs_chnum > 0) ? "En" : "Dis", (via->dxs_src) ? "(SRC)" : "",
 	    via_dxs_chnum, via_sgd_chnum, NWRCHANS);
 
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+	      goto bad;
 
 	return (0);
 bad:
diff --git a/sys/dev/sound/pci/via82c686.c b/sys/dev/sound/pci/via82c686.c
index 44f846b684d7..40f3521a57a2 100644
--- a/sys/dev/sound/pci/via82c686.c
+++ b/sys/dev/sound/pci/via82c686.c
@@ -585,10 +585,11 @@ via_attach(device_t dev)
 		 device_get_nameunit(device_get_parent(dev)));
 
 	/* Register */
-	if (pcm_register(dev, via, 1, 1)) goto bad;
+	pcm_init(dev, via);
 	pcm_addchan(dev, PCMDIR_PLAY, &viachan_class, via);
 	pcm_addchan(dev, PCMDIR_REC, &viachan_class, via);
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto bad;
 	return 0;
 bad:
 	if (via->codec) ac97_destroy(via->codec);
diff --git a/sys/dev/sound/pci/vibes.c b/sys/dev/sound/pci/vibes.c
index e587f0113b5d..7e908f188614 100644
--- a/sys/dev/sound/pci/vibes.c
+++ b/sys/dev/sound/pci/vibes.c
@@ -866,18 +866,17 @@ sv_attach(device_t dev) {
 	if (bootverbose)
 		printf("Sonicvibes: revision %d.\n", sc->rev);
 
-        if (pcm_register(dev, sc, 1, 1)) {
-		device_printf(dev, "sv_attach: pcm_register fail\n");
-                goto fail;
-	}
-
+	pcm_init(dev, sc);
         pcm_addchan(dev, PCMDIR_PLAY, &svpchan_class, sc);
         pcm_addchan(dev, PCMDIR_REC,  &svrchan_class, sc);
 
         snprintf(status, SND_STATUSLEN, "port 0x%jx irq %jd on %s",
                  rman_get_start(sc->enh_reg),  rman_get_start(sc->irq),
 		 device_get_nameunit(device_get_parent(dev)));
-        pcm_setstatus(dev, status);
+	if (pcm_register(dev, status)) {
+		device_printf(dev, "sv_attach: pcm_register fail\n");
+                goto fail;
+	}
 
         DEB(printf("sv_attach: succeeded\n"));
 
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index e03bcab6d8fc..fc9d13593b9e 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -273,53 +273,6 @@ pcm_best_unit(int old)
 	return (best);
 }
 
-int
-pcm_setstatus(device_t dev, char *str)
-{
-	struct snddev_info *d = device_get_softc(dev);
-
-	/* should only be called once */
-	if (d->flags & SD_F_REGISTERED)
-		return (EINVAL);
-
-	PCM_BUSYASSERT(d);
-
-	if (d->playcount == 0 || d->reccount == 0)
-		d->flags |= SD_F_SIMPLEX;
-
-	if (d->playcount > 0 || d->reccount > 0)
-		d->flags |= SD_F_AUTOVCHAN;
-
-	vchan_setmaxauto(d, snd_maxautovchans);
-
-	strlcpy(d->status, str, SND_STATUSLEN);
-	sndstat_register(dev, d->status);
-
-	PCM_LOCK(d);
-
-	/* Done, we're ready.. */
-	d->flags |= SD_F_REGISTERED;
-
-	PCM_RELEASE(d);
-
-	PCM_UNLOCK(d);
-
-	/*
-	 * Create all sysctls once SD_F_REGISTERED is set else
-	 * tunable sysctls won't work:
-	 */
-	pcm_sysinit(dev);
-
-	if (snd_unit_auto < 0)
-		snd_unit_auto = (snd_unit < 0) ? 1 : 0;
-	if (snd_unit < 0 || snd_unit_auto > 1)
-		snd_unit = device_get_unit(dev);
-	else if (snd_unit_auto == 1)
-		snd_unit = pcm_best_unit(snd_unit);
-
-	return (dsp_make_dev(dev));
-}
-
 uint32_t
 pcm_getflags(device_t dev)
 {
@@ -464,9 +417,12 @@ pcm_sysinit(device_t dev)
 		feeder_eq_initsys(dev);
 }
 
-int
-pcm_register(device_t dev, void *devinfo, int numplay __unused,
-    int numrec __unused)
+/*
+ * Basic initialization so that drivers can use pcm_addchan() before
+ * pcm_register().
+ */
+void
+pcm_init(device_t dev, void *devinfo)
 {
 	struct snddev_info *d;
 	int i;
@@ -503,8 +459,53 @@ pcm_register(device_t dev, void *devinfo, int numplay __unused,
 	CHN_INIT(d, channels.pcm);
 	CHN_INIT(d, channels.pcm.busy);
 	CHN_INIT(d, channels.pcm.opened);
+}
 
-	return (0);
+int
+pcm_register(device_t dev, char *str)
+{
+	struct snddev_info *d = device_get_softc(dev);
+
+	/* should only be called once */
+	if (d->flags & SD_F_REGISTERED)
+		return (EINVAL);
+
+	PCM_BUSYASSERT(d);
+
+	if (d->playcount == 0 || d->reccount == 0)
+		d->flags |= SD_F_SIMPLEX;
+
+	if (d->playcount > 0 || d->reccount > 0)
+		d->flags |= SD_F_AUTOVCHAN;
+
+	vchan_setmaxauto(d, snd_maxautovchans);
+
+	strlcpy(d->status, str, SND_STATUSLEN);
+	sndstat_register(dev, d->status);
+
+	PCM_LOCK(d);
+
+	/* Done, we're ready.. */
+	d->flags |= SD_F_REGISTERED;
+
+	PCM_RELEASE(d);
+
+	PCM_UNLOCK(d);
+
+	/*
+	 * Create all sysctls once SD_F_REGISTERED is set else
+	 * tunable sysctls won't work:
+	 */
+	pcm_sysinit(dev);
+
+	if (snd_unit_auto < 0)
+		snd_unit_auto = (snd_unit < 0) ? 1 : 0;
+	if (snd_unit < 0 || snd_unit_auto > 1)
+		snd_unit = device_get_unit(dev);
+	else if (snd_unit_auto == 1)
+		snd_unit = pcm_best_unit(snd_unit);
+
+	return (dsp_make_dev(dev));
 }
 
 int
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index c5013e76034a..1d09c48fc06b 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -245,9 +245,9 @@ int pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction,
 
 int pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo);
 unsigned int pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz);
-int pcm_register(device_t dev, void *devinfo, int numplay, int numrec);
+void pcm_init(device_t dev, void *devinfo);
+int pcm_register(device_t dev, char *str);
 int pcm_unregister(device_t dev);
-int pcm_setstatus(device_t dev, char *str);
 u_int32_t pcm_getflags(device_t dev);
 void pcm_setflags(device_t dev, u_int32_t val);
 void *pcm_getdevinfo(device_t dev);
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index 0a8878c072d2..1f927bcb49de 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -1209,14 +1209,9 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas
 	snprintf(status, sizeof(status), "on %s",
 	    device_get_nameunit(device_get_parent(dev)));
 
-	if (pcm_register(dev, sc,
-	    (sc->sc_play_chan[i].num_alt > 0) ? 1 : 0,
-	    (sc->sc_rec_chan[i].num_alt > 0) ? 1 : 0)) {
-		goto detach;
-	}
+	pcm_init(dev, sc);
 
 	uaudio_pcm_setflags(dev, SD_F_MPSAFE);
-	sc->sc_child[i].pcm_registered = 1;
 
 	if (sc->sc_play_chan[i].num_alt > 0) {
 		sc->sc_play_chan[i].priv_sc = sc;
@@ -1229,7 +1224,9 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas
 		pcm_addchan(dev, PCMDIR_REC, chan_class,
 		    &sc->sc_rec_chan[i]);
 	}
-	pcm_setstatus(dev, status);
+	if (pcm_register(dev, status))
+		goto detach;
+	sc->sc_child[i].pcm_registered = 1;
 
 	uaudio_mixer_register_sysctl(sc, dev, i);