can someone test this?

it allocates storage for the volume change details rather than cast
arguments to a single global task.

adds some safety while there if audio0 is a hotplug device.

ok?

Index: audio.c
===================================================================
RCS file: /cvs/src/sys/dev/audio.c,v
retrieving revision 1.125
diff -u -p -r1.125 audio.c
--- audio.c     19 Dec 2014 22:44:58 -0000      1.125
+++ audio.c     2 Jan 2015 06:08:39 -0000
@@ -465,11 +465,6 @@ audioattach(struct device *parent, struc
        }
        DPRINTF(("audio_attach: inputs ports=0x%x, output ports=0x%x\n",
                 sc->sc_inports.allports, sc->sc_outports.allports));
-
-#if NWSKBD > 0
-       task_set(&sc->sc_mixer_task, wskbd_set_mixervolume_callback, NULL,
-           NULL);
-#endif /* NWSKBD > 0 */
 }
 
 int
@@ -3432,27 +3427,39 @@ filt_audiowrite(struct knote *kn, long h
 }
 
 #if NWSKBD > 0
+struct wskbd_vol_change {
+       struct task t;
+       long dir;
+       long out;
+};
+
 int
 wskbd_set_mixervolume(long dir, long out)
 {
        struct audio_softc *sc;
+       struct wskbd_vol_change *ch;
 
        if (audio_cd.cd_ndevs == 0 || (sc = audio_cd.cd_devs[0]) == NULL) {
                DPRINTF(("wskbd_set_mixervolume: audio_cd\n"));
                return (ENXIO);
        }
 
-       task_del(systq, &sc->sc_mixer_task);
-       task_set(&sc->sc_mixer_task, wskbd_set_mixervolume_callback,
-           (void *)dir, (void *)out);
-       task_add(systq, &sc->sc_mixer_task);
+       ch = malloc(sizeof(*ch), M_TEMP, M_NOWAIT);
+       if (ch == NULL)
+               return (ENOMEM);
+
+       task_set(&ch->t, wskbd_set_mixervolume_callback, ch, NULL);
+       ch->dir = dir;
+       ch->out = out;
+       task_add(systq, &ch->t);
 
        return (0);
 }
 
 void
-wskbd_set_mixervolume_callback(void *arg1, void *arg2)
+wskbd_set_mixervolume_callback(void *xch, void *null)
 {
+       struct wskbd_vol_change *ch = xch;
        struct audio_softc *sc;
        struct au_mixer_ports *ports;
        mixer_devinfo_t mi;
@@ -3461,19 +3468,19 @@ wskbd_set_mixervolume_callback(void *arg
        u_int gain;
        int error;
 
-       if (audio_cd.cd_ndevs == 0 || (sc = audio_cd.cd_devs[0]) == NULL) {
-               DPRINTF(("%s: audio_cd\n", __func__));
-               return;
-       }
+       dir = ch->dir;
+       out = ch->out;
+       free(ch, M_TEMP, sizeof(*ch));
 
-       dir = (long)arg1;
-       out = (long)arg2;
+       sc = (struct audio_softc *)device_lookup(&audio_cd, 0);
+       if (sc == NULL)
+               return;
 
        ports = out ? &sc->sc_outports : &sc->sc_inports;
 
        if (ports->master == -1) {
                DPRINTF(("%s: master == -1\n", __func__));
-               return;
+               goto done;
        }
 
        if (dir == 0) {
@@ -3482,7 +3489,7 @@ wskbd_set_mixervolume_callback(void *arg
                error = au_get_mute(sc, ports, &mute);
                if (error != 0) {
                        DPRINTF(("%s: au_get_mute: %d\n", __func__, error));
-                       return;
+                       goto done;
                }
 
                mute = !mute;
@@ -3490,7 +3497,7 @@ wskbd_set_mixervolume_callback(void *arg
                error = au_set_mute(sc, ports, mute);
                if (error != 0) {
                        DPRINTF(("%s: au_set_mute: %d\n", __func__, error));
-                       return;
+                       goto done;
                }
        } else {
                /* Raise or lower volume */
@@ -3499,7 +3506,7 @@ wskbd_set_mixervolume_callback(void *arg
                error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
                if (error != 0) {
                        DPRINTF(("%s: query_devinfo: %d\n", __func__, error));
-                       return;
+                       goto done;
                }
 
                au_get_gain(sc, ports, &gain, &balance);
@@ -3512,8 +3519,11 @@ wskbd_set_mixervolume_callback(void *arg
                error = au_set_gain(sc, ports, gain, balance);
                if (error != 0) {
                        DPRINTF(("%s: au_set_gain: %d\n", __func__, error));
-                       return;
+                       goto done;
                }
        }
+
+done:
+       device_unref(&sc->dev);
 }
 #endif /* NWSKBD > 0 */

Reply via email to