Add support for mute buttons on USB audio devices and

use the hwvol interface to adjust the mixer settings.

MFC after:	1 week
This commit is contained in:
Hans Petter Selasky 2013-02-07 08:20:03 +00:00
parent 1b3502e5a1
commit 2ba0f36139
3 changed files with 58 additions and 29 deletions

View File

@ -893,14 +893,8 @@ mixer_hwvol_init(device_t dev)
}
void
mixer_hwvol_mute(device_t dev)
mixer_hwvol_mute_locked(struct snd_mixer *m)
{
struct snd_mixer *m;
struct cdev *pdev;
pdev = mixer_get_devt(dev);
m = pdev->si_drv1;
snd_mtxlock(m->lock);
if (m->hwvol_muted) {
m->hwvol_muted = 0;
mixer_set(m, m->hwvol_mixer, m->hwvol_mute_level);
@ -909,19 +903,26 @@ mixer_hwvol_mute(device_t dev)
m->hwvol_mute_level = mixer_get(m, m->hwvol_mixer);
mixer_set(m, m->hwvol_mixer, 0);
}
snd_mtxunlock(m->lock);
}
void
mixer_hwvol_step(device_t dev, int left_step, int right_step)
mixer_hwvol_mute(device_t dev)
{
struct snd_mixer *m;
int level, left, right;
struct cdev *pdev;
pdev = mixer_get_devt(dev);
m = pdev->si_drv1;
snd_mtxlock(m->lock);
mixer_hwvol_mute_locked(m);
snd_mtxunlock(m->lock);
}
void
mixer_hwvol_step_locked(struct snd_mixer *m, int left_step, int right_step)
{
int level, left, right;
if (m->hwvol_muted) {
m->hwvol_muted = 0;
level = m->hwvol_mute_level;
@ -929,15 +930,31 @@ mixer_hwvol_step(device_t dev, int left_step, int right_step)
level = mixer_get(m, m->hwvol_mixer);
if (level != -1) {
left = level & 0xff;
right = level >> 8;
right = (level >> 8) & 0xff;
left += left_step * m->hwvol_step;
if (left < 0)
left = 0;
else if (left > 100)
left = 100;
right += right_step * m->hwvol_step;
if (right < 0)
right = 0;
else if (right > 100)
right = 100;
mixer_set(m, m->hwvol_mixer, left | right << 8);
}
}
void
mixer_hwvol_step(device_t dev, int left_step, int right_step)
{
struct snd_mixer *m;
struct cdev *pdev;
pdev = mixer_get_devt(dev);
m = pdev->si_drv1;
snd_mtxlock(m->lock);
mixer_hwvol_step_locked(m, left_step, right_step);
snd_mtxunlock(m->lock);
}

View File

@ -40,7 +40,9 @@ int mixer_ioctl_cmd(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode, struc
int mixer_oss_mixerinfo(struct cdev *i_dev, oss_mixerinfo *mi);
int mixer_hwvol_init(device_t dev);
void mixer_hwvol_mute_locked(struct snd_mixer *m);
void mixer_hwvol_mute(device_t dev);
void mixer_hwvol_step_locked(struct snd_mixer *m, int l_step, int r_step);
void mixer_hwvol_step(device_t dev, int left_step, int right_step);
int mixer_busy(struct snd_mixer *m);

View File

@ -287,14 +287,17 @@ struct uaudio_hid {
struct usb_xfer *xfer[UAUDIO_HID_N_TRANSFER];
struct hid_location volume_up_loc;
struct hid_location volume_down_loc;
struct hid_location mute_loc;
uint32_t flags;
#define UAUDIO_HID_VALID 0x0001
#define UAUDIO_HID_HAS_ID 0x0002
#define UAUDIO_HID_HAS_VOLUME_UP 0x0004
#define UAUDIO_HID_HAS_VOLUME_DOWN 0x0008
#define UAUDIO_HID_HAS_MUTE 0x0010
uint8_t iface_index;
uint8_t volume_up_id;
uint8_t volume_down_id;
uint8_t mute_id;
};
struct uaudio_softc {
@ -1012,6 +1015,8 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas
goto detach;
sc->sc_mixer_init = 1;
mixer_hwvol_init(dev);
snprintf(status, sizeof(status), "at ? %s", PCM_KLDSTRING(snd_uaudio));
if (pcm_register(dev, sc,
@ -5520,9 +5525,6 @@ uaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error)
struct uaudio_softc *sc = usbd_xfer_softc(xfer);
const uint8_t *buffer = usbd_xfer_get_frame_buffer(xfer, 0);
struct snd_mixer *m;
int v;
int v_l;
int v_r;
uint8_t id;
int actlen;
@ -5543,6 +5545,16 @@ uaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error)
m = sc->sc_mixer_dev;
if ((sc->sc_hid.flags & UAUDIO_HID_HAS_MUTE) &&
(sc->sc_hid.mute_id == id) &&
hid_get_data(buffer, actlen,
&sc->sc_hid.mute_loc)) {
DPRINTF("Mute toggle\n");
mixer_hwvol_mute_locked(m);
}
if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_UP) &&
(sc->sc_hid.volume_up_id == id) &&
hid_get_data(buffer, actlen,
@ -5550,13 +5562,7 @@ uaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error)
DPRINTF("Volume Up\n");
v = mix_get_locked(m, SOUND_MIXER_PCM, &v_l, &v_r);
if (v == 0) {
v = ((v_l + v_r) / 2) + 5;
if (v > 100)
v = 100;
mix_set_locked(m, SOUND_MIXER_PCM, v, v);
}
mixer_hwvol_step_locked(m, 1, 1);
}
if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_DOWN) &&
@ -5566,13 +5572,7 @@ uaudio_hid_rx_callback(struct usb_xfer *xfer, usb_error_t error)
DPRINTF("Volume Down\n");
v = mix_get_locked(m, SOUND_MIXER_PCM, &v_l, &v_r);
if (v == 0) {
v = ((v_l + v_r) / 2) - 5;
if (v < 0)
v = 0;
mix_set_locked(m, SOUND_MIXER_PCM, v, v);
}
mixer_hwvol_step_locked(m, -1, -1);
}
case USB_ST_SETUP:
@ -5641,10 +5641,20 @@ uaudio_hid_probe(struct uaudio_softc *sc,
DPRINTFN(1, "Found Volume Down key\n");
}
if (hid_locate(d_ptr, d_len,
HID_USAGE2(HUP_CONSUMER, 0xE2 /* Mute */),
hid_input, 0, &sc->sc_hid.mute_loc, &flags,
&sc->sc_hid.mute_id)) {
if (flags & HIO_VARIABLE)
sc->sc_hid.flags |= UAUDIO_HID_HAS_MUTE;
DPRINTFN(1, "Found Mute key\n");
}
free(d_ptr, M_TEMP);
if (!(sc->sc_hid.flags & (UAUDIO_HID_HAS_VOLUME_UP |
UAUDIO_HID_HAS_VOLUME_DOWN))) {
UAUDIO_HID_HAS_VOLUME_DOWN |
UAUDIO_HID_HAS_MUTE))) {
DPRINTFN(1, "Did not find any volume related keys\n");
return (-1);
}