From owner-svn-src-all@FreeBSD.ORG Thu Feb 14 10:48:10 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 482F6402; Thu, 14 Feb 2013 10:48:10 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id 2BAA8798; Thu, 14 Feb 2013 10:48:10 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1EAmAGK072150; Thu, 14 Feb 2013 10:48:10 GMT (envelope-from hselasky@svn.freebsd.org) Received: (from hselasky@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1EAm914072140; Thu, 14 Feb 2013 10:48:09 GMT (envelope-from hselasky@svn.freebsd.org) Message-Id: <201302141048.r1EAm914072140@svn.freebsd.org> From: Hans Petter Selasky Date: Thu, 14 Feb 2013 10:48:09 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r246786 - in stable/9/sys/dev: sound/pcm sound/usb usb X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 14 Feb 2013 10:48:10 -0000 Author: hselasky Date: Thu Feb 14 10:48:08 2013 New Revision: 246786 URL: http://svnweb.freebsd.org/changeset/base/246786 Log: MFC r246421 and r246454: Add support for buttons on USB audio devices, like Volume Up, Volume Down and Mute. Reviewed by: mav @ Modified: stable/9/sys/dev/sound/pcm/mixer.c stable/9/sys/dev/sound/pcm/mixer.h stable/9/sys/dev/sound/usb/uaudio.c stable/9/sys/dev/usb/usb_transfer.c stable/9/sys/dev/usb/usbdi.h Directory Properties: stable/9/sys/ (props changed) stable/9/sys/dev/ (props changed) Modified: stable/9/sys/dev/sound/pcm/mixer.c ============================================================================== --- stable/9/sys/dev/sound/pcm/mixer.c Thu Feb 14 10:32:47 2013 (r246785) +++ stable/9/sys/dev/sound/pcm/mixer.c Thu Feb 14 10:48:08 2013 (r246786) @@ -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_ 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); } @@ -1492,3 +1509,30 @@ mixer_get_lock(struct snd_mixer *m) } return (m->lock); } + +int +mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright) +{ + int level; + + level = mixer_get(m, dev); + if (level < 0) { + *pright = *pleft = -1; + return (-1); + } + + *pleft = level & 0xFF; + *pright = (level >> 8) & 0xFF; + + return (0); +} + +int +mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right) +{ + int level; + + level = (left & 0xFF) | ((right & 0xFF) << 8); + + return (mixer_set(m, dev, level)); +} Modified: stable/9/sys/dev/sound/pcm/mixer.h ============================================================================== --- stable/9/sys/dev/sound/pcm/mixer.h Thu Feb 14 10:32:47 2013 (r246785) +++ stable/9/sys/dev/sound/pcm/mixer.h Thu Feb 14 10:48:08 2013 (r246786) @@ -37,11 +37,15 @@ int mixer_ioctl_cmd(struct cdev *i_dev, 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); +int mix_get_locked(struct snd_mixer *m, u_int dev, int *pleft, int *pright); +int mix_set_locked(struct snd_mixer *m, u_int dev, int left, int right); int mix_set(struct snd_mixer *m, u_int dev, u_int left, u_int right); int mix_get(struct snd_mixer *m, u_int dev); int mix_setrecsrc(struct snd_mixer *m, u_int32_t src); Modified: stable/9/sys/dev/sound/usb/uaudio.c ============================================================================== --- stable/9/sys/dev/sound/usb/uaudio.c Thu Feb 14 10:32:47 2013 (r246785) +++ stable/9/sys/dev/sound/usb/uaudio.c Thu Feb 14 10:48:08 2013 (r246786) @@ -71,6 +71,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #define USB_DEBUG_VAR uaudio_debug @@ -277,16 +278,40 @@ struct uaudio_search_result { uint8_t is_input; }; +enum { + UAUDIO_HID_RX_TRANSFER, + UAUDIO_HID_N_TRANSFER, +}; + +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 { struct sbuf sc_sndstat; struct sndcard_func sc_sndcard_func; struct uaudio_chan sc_rec_chan; struct uaudio_chan sc_play_chan; struct umidi_chan sc_midi_chan; + struct uaudio_hid sc_hid; struct uaudio_search_result sc_mixer_clocks; struct uaudio_mixer_node sc_mixer_node; struct mtx *sc_mixer_lock; + struct snd_mixer *sc_mixer_dev; struct usb_device *sc_udev; struct usb_xfer *sc_mixer_xfer[1]; struct uaudio_mixer_node *sc_mixer_root; @@ -407,6 +432,7 @@ static usb_callback_t uaudio_chan_record static usb_callback_t uaudio_mixer_write_cfg_callback; static usb_callback_t umidi_bulk_read_callback; static usb_callback_t umidi_bulk_write_callback; +static usb_callback_t uaudio_hid_rx_callback; /* ==== USB mixer ==== */ @@ -500,6 +526,9 @@ static void umidi_close(struct usb_fifo static void umidi_init(device_t dev); static int umidi_probe(device_t dev); static int umidi_detach(device_t dev); +static int uaudio_hid_probe(struct uaudio_softc *sc, + struct usb_attach_arg *uaa); +static void uaudio_hid_detach(struct uaudio_softc *sc); #ifdef USB_DEBUG static void uaudio_chan_dump_ep_desc( @@ -624,6 +653,18 @@ static const struct usb_config }, }; +static const struct usb_config + uaudio_hid_config[UAUDIO_HID_N_TRANSFER] = { + [UAUDIO_HID_RX_TRANSFER] = { + .type = UE_INTERRUPT, + .endpoint = UE_ADDR_ANY, + .direction = UE_DIR_IN, + .bufsize = 0, /* use wMaxPacketSize */ + .flags = {.short_xfer_ok = 1,}, + .callback = &uaudio_hid_rx_callback, + }, +}; + static devclass_t uaudio_devclass; static device_method_t uaudio_methods[] = { @@ -896,7 +937,7 @@ uaudio_attach(device_t dev) } device_printf(dev, "MIDI sequencer.\n"); } else { - device_printf(dev, "No midi sequencer.\n"); + device_printf(dev, "No MIDI sequencer.\n"); } DPRINTF("doing child attach\n"); @@ -926,6 +967,12 @@ uaudio_attach(device_t dev) goto detach; } + if (uaudio_hid_probe(sc, uaa) == 0) { + device_printf(dev, "HID volume keys found.\n"); + } else { + device_printf(dev, "No HID volume keys found.\n"); + } + /* reload all mixer settings */ uaudio_mixer_reload_all(sc); @@ -968,6 +1015,8 @@ uaudio_attach_sub(device_t dev, kobj_cla 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, @@ -1034,6 +1083,8 @@ uaudio_detach(device_t dev) if (sc->sc_rec_chan.valid) usbd_transfer_unsetup(sc->sc_rec_chan.xfer, UAUDIO_NCHANBUFS + 1); + uaudio_hid_detach(sc); + if (bus_generic_detach(dev) != 0) { DPRINTF("detach failed!\n"); } @@ -1213,6 +1264,18 @@ uaudio_chan_fill_info_sub(struct uaudio_ alt_index++; } + if ((!(sc->sc_hid.flags & UAUDIO_HID_VALID)) && + (id->bInterfaceClass == UICLASS_HID) && + (id->bInterfaceSubClass == 0) && + (id->bInterfaceProtocol == 0) && + (alt_index == 0) && + usbd_get_iface(udev, curidx) != NULL) { + DPRINTF("Found HID interface at %d\n", + curidx); + sc->sc_hid.flags |= UAUDIO_HID_VALID; + sc->sc_hid.iface_index = curidx; + } + uma_if_class = ((id->bInterfaceClass == UICLASS_AUDIO) || ((id->bInterfaceClass == UICLASS_VENDOR) && @@ -2490,6 +2553,9 @@ uaudio_mixer_reload_all(struct uaudio_so pmc->update[chan / 8] |= (1 << (chan % 8)); } usbd_transfer_start(sc->sc_mixer_xfer[0]); + + /* start HID volume keys, if any */ + usbd_transfer_start(sc->sc_hid.xfer[0]); mtx_unlock(sc->sc_mixer_lock); } @@ -4818,6 +4884,7 @@ uaudio_mixer_init_sub(struct uaudio_soft DPRINTF("\n"); sc->sc_mixer_lock = mixer_get_lock(m); + sc->sc_mixer_dev = m; if (usbd_transfer_setup(sc->sc_udev, &sc->sc_mixer_iface_index, sc->sc_mixer_xfer, uaudio_mixer_config, 1, sc, @@ -5452,6 +5519,167 @@ umidi_detach(device_t dev) return (0); } +static void +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; + uint8_t id; + int actlen; + + usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL); + + switch (USB_GET_STATE(xfer)) { + case USB_ST_TRANSFERRED: + DPRINTF("actlen=%d\n", actlen); + + if (actlen != 0 && + (sc->sc_hid.flags & UAUDIO_HID_HAS_ID)) { + id = *buffer; + buffer++; + actlen--; + } else { + id = 0; + } + + 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, + &sc->sc_hid.volume_up_loc)) { + + DPRINTF("Volume Up\n"); + + mixer_hwvol_step_locked(m, 1, 1); + } + + if ((sc->sc_hid.flags & UAUDIO_HID_HAS_VOLUME_DOWN) && + (sc->sc_hid.volume_down_id == id) && + hid_get_data(buffer, actlen, + &sc->sc_hid.volume_down_loc)) { + + DPRINTF("Volume Down\n"); + + mixer_hwvol_step_locked(m, -1, -1); + } + + case USB_ST_SETUP: +tr_setup: + /* check if we can put more data into the FIFO */ + usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer)); + usbd_transfer_submit(xfer); + break; + + default: /* Error */ + if (error != USB_ERR_CANCELLED) { + /* try clear stall first */ + usbd_xfer_set_stall(xfer); + goto tr_setup; + } + break; + } +} + +static int +uaudio_hid_probe(struct uaudio_softc *sc, + struct usb_attach_arg *uaa) +{ + void *d_ptr; + uint32_t flags; + uint16_t d_len; + uint8_t id; + int error; + + if (!(sc->sc_hid.flags & UAUDIO_HID_VALID)) + return (-1); + + if (sc->sc_mixer_lock == NULL) + return (-1); + + /* Get HID descriptor */ + error = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr, + &d_len, M_TEMP, sc->sc_hid.iface_index); + + if (error) { + DPRINTF("error reading report description\n"); + return (-1); + } + + /* check if there is an ID byte */ + hid_report_size(d_ptr, d_len, hid_input, &id); + + if (id != 0) + sc->sc_hid.flags |= UAUDIO_HID_HAS_ID; + + if (hid_locate(d_ptr, d_len, + HID_USAGE2(HUP_CONSUMER, 0xE9 /* Volume Increment */), + hid_input, 0, &sc->sc_hid.volume_up_loc, &flags, + &sc->sc_hid.volume_up_id)) { + if (flags & HIO_VARIABLE) + sc->sc_hid.flags |= UAUDIO_HID_HAS_VOLUME_UP; + DPRINTFN(1, "Found Volume Up key\n"); + } + + if (hid_locate(d_ptr, d_len, + HID_USAGE2(HUP_CONSUMER, 0xEA /* Volume Decrement */), + hid_input, 0, &sc->sc_hid.volume_down_loc, &flags, + &sc->sc_hid.volume_down_id)) { + if (flags & HIO_VARIABLE) + sc->sc_hid.flags |= UAUDIO_HID_HAS_VOLUME_DOWN; + 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_MUTE))) { + DPRINTFN(1, "Did not find any volume related keys\n"); + return (-1); + } + + /* prevent the uhid driver from attaching */ + usbd_set_parent_iface(uaa->device, sc->sc_hid.iface_index, + sc->sc_mixer_iface_index); + + /* allocate USB transfers */ + error = usbd_transfer_setup(uaa->device, &sc->sc_hid.iface_index, + sc->sc_hid.xfer, uaudio_hid_config, UAUDIO_HID_N_TRANSFER, + sc, sc->sc_mixer_lock); + if (error) { + DPRINTF("error=%s\n", usbd_errstr(error)); + return (-1); + } + return (0); +} + +static void +uaudio_hid_detach(struct uaudio_softc *sc) +{ + usbd_transfer_unsetup(sc->sc_hid.xfer, UAUDIO_HID_N_TRANSFER); +} + DRIVER_MODULE(uaudio, uhub, uaudio_driver, uaudio_devclass, NULL, 0); MODULE_DEPEND(uaudio, usb, 1, 1, 1); MODULE_DEPEND(uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); Modified: stable/9/sys/dev/usb/usb_transfer.c ============================================================================== --- stable/9/sys/dev/usb/usb_transfer.c Thu Feb 14 10:32:47 2013 (r246785) +++ stable/9/sys/dev/usb/usb_transfer.c Thu Feb 14 10:48:08 2013 (r246786) @@ -1923,6 +1923,17 @@ usbd_xfer_get_frame(struct usb_xfer *xfe return (&xfer->frbuffers[frindex]); } +void * +usbd_xfer_get_frame_buffer(struct usb_xfer *xfer, usb_frcount_t frindex) +{ + struct usb_page_search page_info; + + KASSERT(frindex < xfer->max_frame_count, ("frame index overflow")); + + usbd_get_page(&xfer->frbuffers[frindex], 0, &page_info); + return (page_info.buffer); +} + /*------------------------------------------------------------------------* * usbd_xfer_get_fps_shift * Modified: stable/9/sys/dev/usb/usbdi.h ============================================================================== --- stable/9/sys/dev/usb/usbdi.h Thu Feb 14 10:32:47 2013 (r246785) +++ stable/9/sys/dev/usb/usbdi.h Thu Feb 14 10:48:08 2013 (r246786) @@ -522,6 +522,7 @@ void usbd_xfer_status(struct usb_xfer *x int *aframes, int *nframes); struct usb_page_cache *usbd_xfer_get_frame(struct usb_xfer *xfer, usb_frcount_t frindex); +void *usbd_xfer_get_frame_buffer(struct usb_xfer *, usb_frcount_t); void *usbd_xfer_softc(struct usb_xfer *xfer); void *usbd_xfer_get_priv(struct usb_xfer *xfer); void usbd_xfer_set_priv(struct usb_xfer *xfer, void *);